diff --git a/ChangeLog.markdown b/ChangeLog.markdown
new file mode 100644
--- /dev/null
+++ b/ChangeLog.markdown
@@ -0,0 +1,240 @@
+v3.5.7
+--------
+
+The major change in this release is support for explicit renaming macros. This low-level macro system provides the ability to break macro hygiene, if necessary, and offers a macro system that is similar to `defmacro`.
+
+In addition, all of the character functions from R<sup>5</sup>RS have been implemented.
+
+v3.5.6
+--------
+
+- Enhanced the compiler to accept `load-ffi` as a special form, so a compiled version of a program does not have to wait for a module to be dynamically loaded. Instead, the module is included at compile time. This offers a nice speed improvement:
+
+  <pre>
+  <code>
+     $ time huski ffi-cputime.scm 
+     Seconds of CPU time spent: 2.756171
+
+     $ time ./ffi-cputime 
+     Seconds of CPU time spent: 2.4001e-2
+  </code>
+  </pre>
+
+- Allow a hash table to be defined directly using `#hash(alist)` - for example, `#hash()` for an empty table or `#hash((a 1) (b . 2))` for a table with two elements. This is not part of R<sup>5</sup>RS but seems less clumsy than the standard way, and a similar language feature is provided by Racket.
+- Added support for `hash-table-set!` and `hash-table-delete!` to the compiler.
+- Fixed a bug where `integer?` would always return false for negative rational numbers. For example, `(integer? -2/2)` should evaluate to `#t`.
+
+v3.5.5
+--------
+
+- Added support for SRFI-1 (List Library), which can be loaded using `(require-extension (srfi 1))`. Note that linear update functions (such as `map!`, `take!`, etc) and circular lists are not supported at this time.
+- Added a new LispVal type called `Opaque` for Haskell integration, courtesy of Josh Triplett. The Opaque type allows a native Haskell function to package an arbitrary Haskell type for use by other native code called by husk. See `examples/ffi/Opaque.hs` for an example of how to use this feature.
+- Implemented `file-exists?`, `delete-file`, `char-ready?`, `rationalize`, `gcd`, and `lcm`.
+- Enhanced the parser to read numbers in scientific notation such as `1e3` and `4.2e1`.
+- Modified `numerator` and `denominator` to add support for integers and floating point numbers.
+- Fixed a bug in `set-cdr!` where an unsimplified list may be output. For example, `(3 . (2 . (1 . ())))` instead of `(3 2 1)`.
+- Allow `apply` to receive multiple arguments, as long as the last one is a list.
+
+v3.5.4
+--------
+
+- Enhanced `huski` and `huskc` to print errors to console when a runtime exception occurs,
+and to not print any results to console unless the user calls an I/O function
+such as `write` or `display`.
+- Added a special form `expand` that can be used to see the result of a macro
+expansion, for debugging purposes. For example: `(expand (let ((x 1)) x))`.
+- Allow a list to be enclosed by matched brackets as well as parentheses. For example: `(+ 1 2 [+ 3 4])`.
+- Internal change - cleaned up code by using Language pragmas instead of explicitly using extensions in the cabal and make files.
+
+v3.5.3.2
+--------
+
+- Modified huski to escape baskslashes in the path to the standard library, to guarantee stdlib is loaded when husk is installed on a Windows machine.
+
+v3.5.3.1
+--------
+
+- Removed an unnecessary dependency on `/dev/null` to allow `huski` to interpret files when run on Windows.
+- Prevent divide-by-zero errors when dividing by a single number, or processing a rational number with zero as the denominator.
+
+v3.5.3
+------
+This release adds full support for GHC 7.2.2 / 7.4.1 as well as a number of small enhancements.
+
+- Fixed the FFI to work in both GHC 7.2.2 and GHC 7.4.1.
+- Implemented SRFI 23, which adds error reporting via the `(error)` function.
+- Added support for `let-syntax`, `letrec-syntax`, `set-car!`, `set-cdr!`, `vector-set!`, and `lambda` (pair syntax) to the huskc compiler.
+- Added the `--dynamic` option to the compiler to use dynamic Haskell libraries.
+- Added the `--extra` option to the compiler to allow passing of arbitrary arguments directly to ghc.
+- Fixed huski to allow any redefinition of `let-syntax` and `letrec-syntax`.
+
+v3.5.2.x
+------
+This is a series of quick bug-fix releases that allows husk to build under GHC 7.4.1.
+
+v3.5.2
+------
+- Added an experimental compiler, huskc. For more information see [Issue #62](https://github.com/justinethier/husk-scheme/issues/62).
+- Streamlined the cabal file so that each source file is only compiled a single time.
+
+v3.5.1
+------
+- Improved support for comparing instances of functions using `eq?`, `eqv?`, etc.
+- Reduced variable access time by using a Map to store variables within an environment. 
+- Various internal changes such as renaming the tests directory and integrating R<sup>5</sup>RS pitfalls with the unit tests.
+
+v3.4.4
+------
+This release continues the trend of quick point releases for the 3.4.x series. The key change is support for GHC 7.2: 
+
+- husk now compiles in GHC 7.2. This ended up being a simple change - I had mis-interpreted the value of a pre-processor directive. Sorry about that!
+- Replaced the definition of `letrec` with the macro from R<sup>5</sup>RS.
+- Allow a continuation to call into another continuation via call/cc - see R<sup>5</sup>RS pitfall 1.2
+
+v3.4.3
+------
+- Fixed `let-syntax` and `letrec-syntax` to prevent conflicts between identifiers of the same name in the outer scope and within the macro body.
+- Per R5RS, `(if <test> <consequent>)` is supposed to evaluate `<consequent>` for any value of `<test>` except `#f`. However, husk was only allowing `<test>` to pass if it was equal to `#t`. This has been fixed.
+- Modified `(append)` to accept an arbitrary number of arguments, per R<sup>5</sup>RS.
+- Replaced the macro for `case` with the one from R<sup>5</sup>RS.
+
+v3.4.2
+------
+- Many improvements and bug fixes for let-syntax and letrec-syntax.
+- Improved handling of define and set! within a macro definition.
+
+v3.4.1
+------
+Added experimental support for let-syntax and letrec-syntax.
+
+Bug fixes:
+
+- Fixed a nasty issue where the macro pattern matching code would not properly reset itself when transcribing a macro containing an ellipsis in the middle of a list. For example: `(a ... b c)`. This caused the expanded macro to be incomplete and/or malformed.
+- Fixed a bug that would cause the evaluator to terminate if define-syntax was called within a nested scope. 
+
+v3.4
+----
+This release adds the first hygienic macro support to husk. There are two "sides" to macro hygiene:
+
+- Hygiene: Names that are introduced by the macro do not clash with names in sub-expressions that are passed from user code to it
+- Referential transparency: names that the macro references are coming from the lexical context of its definition, rather than the lexical context of its use
+
+Support has been added for both sides, although there are some issues as noted in the [Version 3.4.x Milestones](https://github.com/justinethier/husk-scheme/issues?milestone=9&state=open). Macro support will continue to improve in future releases.
+
+In addition, this release contains the following bug fixes:
+
+- When searching for a redefinition of a special form, the code now
+recursively examines parent environments instead of only inspecting the
+current environment.
+- `(let*)` is now defined in terms of the definition from R<sup>5</sup>RS, to
+fix problems with valid inputs not being matched by `(let*)`.
+
+v3.3
+----
+This release includes major improvements to the macro module.
+In particular:
+
+- husk now supports arbitrary nesting levels of macro 0-or-many matches (IE: `...`). Previous versions would not handle macros that had more than 2 nesting levels of 0-or-more matches.
+- Macros now correctly handle improper lists. Previous versions of husk did not respect the fact that the trailing item in an improper list may be matched zero or more times. Also, husk macros now properly convert the transformed code into improper or proper lists depending upon the pattern, input, and transform.
+- (do) is now defined in terms of the macro from R<sup>5</sup>RS.
+
+Other changes:
+
+- Updated the parser to simplify improper lists; for example the following input: `'(1 2 . (3 . ()))` will now be converted to `(1 2 3)`
+- Corrected the order of arguments to (fold). For example, the expression (fold (lambda (x y) x) 8 (list 1 2 3)) should yield 3, however in previous releases husk would incorrectly yield 8 because of the order of arguments.
+
+v3.2.1
+------
+- Added a conditional compilation check to allow husk to build on GHC 6 and GHC 7.
+
+v3.2
+----
+- Significant improvements to the parser, including proper handling of whitespace and comments. This represents a critical upgrade from the previous releases.
+- Added support for nested block comments using `#|` and `|#`, per the R<sup>7</sup>RS draft.
+- Added `hash-table-fold`
+
+v3.1
+----
+- Fixed issues with lexical scope, where proper scope was not observed for
+special forms, including: if, cond, set!, begin, define, lambda, set-car!,
+set-cdr!, string-set!, vector-set!, and hash-table-set! - For example: 
+
+`(let ((if +)) (if 1 2 3))` was 2 instead of 6. Now it eval's to 6
+
+- `cond`, `and`, and `or` are now defined using the corresponding macros from R<sup>5</sup>RS,
+  to give them the expected semantics.
+- Added a `gensym` primitive.
+- Internal change - relocated primitive functions to a new Language.Scheme.Primitives module.
+- Marked macro support as non-hygienic since hygiene is not fully supported at present.
+
+v3.0
+----
+- Added a foreign function interface (FFI) to allow husk to call directly into Haskell code.
+
+v2.4
+----
+- Simplified the core evaluator by moving several functions out of eval.
+Practically, this means that the following functions are now first-class objects:
+apply, call-with-current-continuation, call-with-values, eval, and load. 
+They can be called directly, assigned to variables, etc just like any
+other first-class value. 
+- (call-with-values) now accepts multiple return values from the producer function.
+- If (values) is called with multiple arguments and is not part of an
+enclosing (call-with-values), the first value is returned to the interpreter
+instead of generating an error.
+- Added additional error handling for set! - and related functions - when these
+functions are called with the wrong number or type of arguments.
+- Added limited support for (dynamic-wind).
+- The parser now recognizes rational number components of a complex number.
+For example: 1/2+3/4i
+
+v2.3
+----
+- Automatically load the scheme standard library when running .scm files.
+- Suppress excess output when running a program by piping it to /dev/null.
+- Added missing I/O functions, including display, input-port?, output-port?,
+newline, write-char, read-char, peek-char, current-input-port,
+current-output-port, call-with-input-file, and call-with-output-port.
+- Added eval.
+- Added a limited version of (call-with-values) that currently only accepts
+one argument.
+
+v2.2
+----
+- Added vector support to macros.
+- Added an example program to demonstrate file I/O: examples/simple-file-io.scm.
+
+v2.1
+----
+- Moved all Haskell code from the 'Scheme' namespace to the 'Language/Scheme'
+namespace.
+- Fixed cases where backquoting of a vector would crash the interpreter.
+- Prevent interpreter from crashing when calling (load) if the file does not
+exist.
+- Improved support of different numeric types across the numerical functions.
+- Added support for binary numbers to (number->string)
+- Implemented (alist->hash-table)
+
+v2.0
+----
+- Full implementation of continuations via call/cc. This involved passing a new continuation type through all versions of the eval function.
+- Fixed a bug where a macro pattern would be incorrectly matched even though a literal identifier in the pattern was not present in the input.
+- Added over 100 new Scheme test cases from the R5RS language specification.
+- Added set-cdr!
+- Changed the banner text on startup to match the new husk logo.
+
+v1.3
+----
+- Added limited support for continuations, by adding the call/cc keyword and first-class continuations. This is still a work in progress, and only a subset of continuations are supported - continuations can only be used as escape procedures from a function (along the lines of a 'return' call).
+
+v1.2
+----
+- Fixed an ugly bug where the underlying functions used to mutate variabiables in (define), (set!), etc implemented dynamic scoping instead of the lexical (static) scoping required by R5RS. [This reference implementation](http://web.mit.edu/kmill/Public/lilscheme.hs) written by Kyle Miller was used as a starting point.
+
+v1.1
+----
+- Many improvements to quasi-quotation, including support for unquote splicing (,@).
+
+v1.0
+----
+- Initial release
diff --git a/hs-src/Compiler/huskc.hs b/hs-src/Compiler/huskc.hs
--- a/hs-src/Compiler/huskc.hs
+++ b/hs-src/Compiler/huskc.hs
@@ -130,7 +130,7 @@
 -- |High level code to compile the given file
 process :: String -> String -> Bool -> String -> IO ()
 process inFile outExec dynamic extraArgs = do
-  env <- liftIO $ nullEnv
+  env <- Language.Scheme.Core.primitiveBindings
   stdlib <- getDataFileName "stdlib.scm"
   srfi55 <- getDataFileName "srfi/srfi-55.scm" -- (require-extension)
   result <- (runIOThrows $ liftM show $ compileSchemeFile env stdlib srfi55 inFile)
diff --git a/hs-src/Language/Scheme/Compiler.hs b/hs-src/Language/Scheme/Compiler.hs
--- a/hs-src/Language/Scheme/Compiler.hs
+++ b/hs-src/Language/Scheme/Compiler.hs
@@ -22,6 +22,7 @@
 -}
 
 module Language.Scheme.Compiler where 
+import qualified Language.Scheme.Core (apply)
 import qualified Language.Scheme.Macro
 -- import Language.Scheme.Numerical
 -- import Language.Scheme.Parser
@@ -35,7 +36,7 @@
 import qualified Data.Map
 import Data.Ratio
 -- import System.IO
--- import Debug.Trace
+--import Debug.Trace
 
 -- A type to store options passed to compile
 -- eventually all of this might be able to be integrated into a Compile monad
@@ -210,7 +211,7 @@
 
 compile env (List [Atom "expand",  _body]) copts = do
   -- TODO: check if expand has been rebound?
-  val <- Language.Scheme.Macro.expand env False _body
+  val <- Language.Scheme.Macro.expand env False _body Language.Scheme.Core.apply
   compileScalar (" return $ " ++ astToHaskellStr val) copts
 
 compile env (List (Atom "let-syntax" : List _bindings : _body)) copts = do
@@ -218,7 +219,7 @@
   bodyEnv <- liftIO $ extendEnv env []
   _ <- Language.Scheme.Macro.loadMacros env bodyEnv Nothing False _bindings
   -- Expand whole body as a single continuous macro, to ensure hygiene
-  expanded <- Language.Scheme.Macro.expand bodyEnv False $ List _body  
+  expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) Language.Scheme.Core.apply
   case expanded of
     List e -> compile bodyEnv (List $ Atom "begin" : e) copts
     e -> compile bodyEnv e copts
@@ -228,11 +229,22 @@
   bodyEnv <- liftIO $ extendEnv env []
   _ <- Language.Scheme.Macro.loadMacros bodyEnv bodyEnv Nothing False _bindings
   -- Expand whole body as a single continuous macro, to ensure hygiene
-  expanded <- Language.Scheme.Macro.expand bodyEnv False $ List _body  
+  expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) Language.Scheme.Core.apply
   case expanded of
     List e -> compile bodyEnv (List $ Atom "begin" : e) copts
     e -> compile bodyEnv e copts
 
+compile env (List [Atom "define-syntax", Atom keyword,
+  (List [Atom "er-macro-transformer", 
+    (List (Atom "lambda" : List fparams : fbody))])])
+  copts = do
+
+  -- TODO: same as below, these defs will eventually need to 
+  -- be made available during runtime as well as compile time
+  f <- makeNormalFunc env fparams fbody 
+  _ <- defineNamespacedVar env macroNamespace keyword $ SyntaxExplicitRenaming f
+  compileScalar ("  return $ Nil \"\"") copts 
+
 compile env (List [Atom "define-syntax", Atom keyword, (List (Atom "syntax-rules" : (List identifiers : rules)))]) copts = do
 --
 -- TODO:
@@ -277,6 +289,10 @@
  Atom symMakeDefine <- _gensym "setFuncMakeSet"
 
  -- Store var in huskc's env for macro processing
+ --
+ -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ -- TODO: this is going to cause problems for er macros
+ --
  -- TODO: changed this to a 'defineVar' for now, because without lambda forms inserting
  --       defined variables, using setVar will cause an error when trying to set a
  --       lambda var...
@@ -319,9 +335,8 @@
  compiledParams <- compileLambdaList fparams
  compiledBody <- compileBlock symCallfunc Nothing env [] fbody
 
--- TODO:
--- -- Store var in huskc's env for macro processing (and same for other vers of define)
--- _ <- defineVar e var form
+ -- Store var in huskc's env for macro processing (and same for other vers of define)
+ _ <- makeNormalFunc env fparams fbody >>= defineVar env var
 
  -- Entry point; ensure var is not rebound
  f <- return $ [AstValue $ "  bound <- liftIO $ isRecBound env \"define\"",
@@ -338,9 +353,8 @@
  compiledParams <- compileLambdaList fparams
  compiledBody <- compileBlock symCallfunc Nothing env [] fbody
 
--- TODO:
--- -- Store var in huskc's env for macro processing (and same for other vers of define)
--- _ <- defineVar e var form
+ -- Store var in huskc's env for macro processing (and same for other vers of define)
+ _ <- makeVarargs varargs env fparams fbody >>= defineVar env var
 
  -- Entry point; ensure var is not rebound
  f <- return $ [AstValue $ "  bound <- liftIO $ isRecBound env \"define\"",
@@ -621,15 +635,13 @@
 mcompile env lisp copts = mfunc env lisp compile copts
 mfunc :: Env -> LispVal -> (Env -> LispVal -> CompOpts -> IOThrowsError [HaskAST]) -> CompOpts -> IOThrowsError [HaskAST] 
 mfunc env lisp func copts = do
-  transformed <- Language.Scheme.Macro.macroEval env lisp 
+  transformed <- Language.Scheme.Macro.macroEval env lisp Language.Scheme.Core.apply
   func env transformed copts
+
 {- TODO: adapt for compilation
 meval, mprepareApply :: Env -> LispVal -> LispVal -> IOThrowsError LispVal
 meval env cont lisp = mfunc env cont lisp eval
 mprepareApply env cont lisp = mfunc env cont lisp prepareApply
-mfunc :: Env -> LispVal -> LispVal -> (Env -> LispVal -> LispVal -> IOThrowsError LispVal) -> IOThrowsError LispVal
-mfunc env cont lisp func = do
-  Language.Scheme.Macro.macroEval env lisp >>= (func env cont) 
 -}
 
 
diff --git a/hs-src/Language/Scheme/Core.hs b/hs-src/Language/Scheme/Core.hs
--- a/hs-src/Language/Scheme/Core.hs
+++ b/hs-src/Language/Scheme/Core.hs
@@ -40,13 +40,14 @@
 import Language.Scheme.Variables
 import Control.Monad.Error
 import Data.Array
+import qualified Data.Char
 import qualified Data.Map
 import qualified System.Exit
 import System.IO
 
 -- |husk version number
 version :: String
-version = "3.5.6"
+version = "3.5.7"
 
 -- |A utility function to display the husk console banner
 showBanner :: IO ()
@@ -104,7 +105,7 @@
 mprepareApply env cont lisp = mfunc env cont lisp prepareApply
 mfunc :: Env -> LispVal -> LispVal -> (Env -> LispVal -> LispVal -> IOThrowsError LispVal) -> IOThrowsError LispVal
 mfunc env cont lisp func = do
-  Language.Scheme.Macro.macroEval env lisp >>= (func env cont) 
+  Language.Scheme.Macro.macroEval env lisp apply >>= (func env cont) 
 {- OBSOLETE:
  old code for updating env's in the continuation chain (see below)
   if False --needToExtendEnv lisp
@@ -311,7 +312,7 @@
  bound <- liftIO $ isRecBound env "expand"
  if bound
   then prepareApply env cont args -- if bound to a variable in this scope; call into it
-  else Language.Scheme.Macro.expand env False _body >>= continueEval env cont
+  else Language.Scheme.Macro.expand env False _body apply >>= continueEval env cont
  
 -- A rudimentary implementation of let-syntax
 eval env cont args@(List (Atom "let-syntax" : List _bindings : _body)) = do
@@ -322,7 +323,7 @@
    bodyEnv <- liftIO $ extendEnv env []
    _ <- Language.Scheme.Macro.loadMacros env bodyEnv Nothing False _bindings
    -- Expand whole body as a single continuous macro, to ensure hygiene
-   expanded <- Language.Scheme.Macro.expand bodyEnv False $ List _body  
+   expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) apply
    case expanded of
      List e -> continueEval bodyEnv (Continuation bodyEnv (Just $ SchemeBody e) (Just cont) Nothing Nothing) $ Nil "" 
      e -> continueEval bodyEnv cont e
@@ -339,14 +340,29 @@
    -- for now...
    _ <- Language.Scheme.Macro.loadMacros bodyEnv bodyEnv Nothing False _bindings
    -- Expand whole body as a single continuous macro, to ensure hygiene
-   expanded <- Language.Scheme.Macro.expand bodyEnv False $ List _body  
+   expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) apply
    case expanded of
      List e -> continueEval bodyEnv (Continuation bodyEnv (Just $ SchemeBody e) (Just cont) Nothing Nothing) $ Nil "" 
      e -> continueEval bodyEnv cont e
 
-eval env cont args@(List [Atom "define-syntax", Atom keyword, (List (Atom "syntax-rules" : (List identifiers : rules)))]) = do
+eval env cont args@(List [Atom "define-syntax", Atom keyword,
+  (List [Atom "er-macro-transformer", 
+    (List (Atom "lambda" : List fparams : fbody))])]) = do
  bound <- liftIO $ isRecBound env "define-syntax"
  if bound
+  then prepareApply env cont args -- if bound to var in this scope; call it
+  else do 
+    -- TODO: ensure fparams is 3 atoms
+    -- TODO: now just need to figure out initial entry point to the ER func
+    --       for now can ignore complications of an ER found during syn-rules transformation
+    f <- makeNormalFunc env fparams fbody 
+    _ <- defineNamespacedVar env macroNamespace keyword $ SyntaxExplicitRenaming f
+    continueEval env cont $ Nil "" 
+
+eval env cont args@(List [Atom "define-syntax", Atom keyword, 
+    (List (Atom "syntax-rules" : (List identifiers : rules)))]) = do
+ bound <- liftIO $ isRecBound env "define-syntax"
+ if bound
   then prepareApply env cont args -- if bound to a variable in this scope; call into it
   else do 
   {-
@@ -1003,6 +1019,26 @@
               ("string-ci>?", stringCIBoolBinop (>)),
               ("string-ci<=?", stringCIBoolBinop (<=)),
               ("string-ci>=?", stringCIBoolBinop (>=)),
+
+              ("char=?",  charBoolBinop (==)),
+              ("char<?",  charBoolBinop (<)),
+              ("char>?",  charBoolBinop (>)),
+              ("char<=?", charBoolBinop (<=)),
+              ("char>=?", charBoolBinop (>=)),
+              ("char-ci=?",  charCIBoolBinop (==)),
+              ("char-ci<?",  charCIBoolBinop (<)),
+              ("char-ci>?",  charCIBoolBinop (>)),
+              ("char-ci<=?", charCIBoolBinop (<=)),
+              ("char-ci>=?", charCIBoolBinop (>=)),
+              ("char-alphabetic?", charPredicate Data.Char.isAlpha),
+              ("char-numeric?", charPredicate Data.Char.isNumber),
+              ("char-whitespace?", charPredicate Data.Char.isSpace),
+              ("char-upper-case?", charPredicate Data.Char.isUpper),
+              ("char-lower-case?", charPredicate Data.Char.isLower),
+              ("char->integer", char2Int),
+              ("integer->char", int2Char),
+              ("char-upper", charUpper),
+              ("char-lower", charLower),
 
               ("car", car),
               ("cdr", cdr),
diff --git a/hs-src/Language/Scheme/Macro.hs b/hs-src/Language/Scheme/Macro.hs
--- a/hs-src/Language/Scheme/Macro.hs
+++ b/hs-src/Language/Scheme/Macro.hs
@@ -48,6 +48,7 @@
     ) where
 import Language.Scheme.Types
 import Language.Scheme.Variables
+import Language.Scheme.Macro.ExplicitRenaming
 import qualified Language.Scheme.Macro.Matches as Matches
 import Language.Scheme.Primitives (_gensym)
 import Control.Monad.Error
@@ -105,6 +106,8 @@
 --  Otherwise the input is returned unchanged.
 macroEval :: Env        -- ^Current environment for the AST
           -> LispVal    -- ^AST to search
+          -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Eval func
+
           -> IOThrowsError LispVal -- ^Transformed AST containing an
                                    -- expanded macro if found
 
@@ -117,28 +120,42 @@
  -  begins with the keyword for the macro." 
  -
  -}
-macroEval env lisp@(List (Atom x : _)) = do
+macroEval env lisp@(List (Atom x : _)) apply = do
   -- Note: If there is a procedure of the same name it will be shadowed by the macro.
   isDefined <- liftIO $ isNamespacedRecBound env macroNamespace x
   if isDefined
      then do
-       Syntax (Just defEnv) _ definedInMacro identifiers rules <- getNamespacedVar env macroNamespace x
-       renameEnv <- liftIO $ nullEnv -- Local environment used just for this invocation
-                                     -- to hold renamed variables
-       cleanupEnv <- liftIO $ nullEnv -- Local environment used just for this invocation
-                                      -- to hold new symbols introduced by renaming. We
-                                      -- can use this to clean up any left after transformation
+       var <- getNamespacedVar env macroNamespace x
+       case var of
+         -- Explicit Renaming
+         SyntaxExplicitRenaming transformer@(Func _ _ _ _) -> do
+           renameEnv <- liftIO $ nullEnv -- Local environment used just for this
+           expanded <- explicitRenamingTransform env renameEnv 
+                                               lisp transformer apply
+           macroEval env expanded apply
 
-       -- Transform the input and then call macroEval again, since a macro may be contained within...
-       expanded <- macroTransform defEnv env env renameEnv cleanupEnv 
-                                  definedInMacro 
-                                 (List identifiers) rules lisp
-       macroEval env expanded -- Useful debug to see all exp's: (trace ("exp = " ++ show expanded) expanded)
---       macroEval env (trace ("exp = " ++ show expanded) expanded)
+         -- Syntax Rules
+         Syntax (Just defEnv) _ definedInMacro identifiers rules -> do
+           renameEnv <- liftIO $ nullEnv -- Local environment used just for this
+                                         -- invocation to hold renamed variables
+           cleanupEnv <- liftIO $ nullEnv -- Local environment used just for 
+                                          -- this invocation to hold new symbols
+                                          -- introduced by renaming. We can use
+                                          -- this to clean up any left after 
+                                          -- transformation
+
+           -- Transform the input and then call macroEval again, 
+           -- since a macro may be contained within...
+           expanded <- macroTransform defEnv env env renameEnv cleanupEnv 
+                                      definedInMacro 
+                                     (List identifiers) rules lisp apply
+           macroEval env expanded apply
+           -- Useful debug to see all exp's:
+           -- macroEval env (trace ("exp = " ++ show expanded) expanded)
      else return lisp
 
 -- No macro to process, just return code as it is...
-macroEval _ lisp@(_) = return lisp
+macroEval _ lisp@(_) _ = return lisp
 
 {-
  - Given input and syntax-rules, determine if any rule is a match and transform it.
@@ -152,20 +169,31 @@
  -  rules - pattern/transform pairs to compare to input
  -  input - Code from the scheme application 
  -}
-macroTransform :: Env -> Env -> Env -> Env -> Env -> Bool -> LispVal -> [LispVal] -> LispVal -> IOThrowsError LispVal
-macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers (rule@(List _) : rs) input = do
+macroTransform :: 
+     Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Bool 
+  -> LispVal 
+  -> [LispVal] 
+  -> LispVal 
+  -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Apply func
+  -> IOThrowsError LispVal
+macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers (rule@(List _) : rs) input apply = do
   localEnv <- liftIO $ nullEnv -- Local environment used just for this invocation
                                -- to hold pattern variables
   result <- matchRule defEnv env divertEnv dim identifiers localEnv renameEnv cleanupEnv rule input
   case (result) of
     -- No match, check the next rule
-    Nil _ -> macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers rs input
+    Nil _ -> macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers rs input apply
     _ -> do
         -- Walk the resulting code, performing the Clinger algorithm's 4 components
-        walkExpanded defEnv env divertEnv renameEnv cleanupEnv dim True False (List []) (result)
+        walkExpanded defEnv env divertEnv renameEnv cleanupEnv dim True False (List []) (result) apply
 
 -- Ran out of rules to match...
-macroTransform _ _ _ _ _ _ _ _ input = throwError $ BadSpecialForm "Input does not match a macro pattern" input
+macroTransform _ _ _ _ _ _ _ _ input _ = throwError $ BadSpecialForm "Input does not match a macro pattern" input
 
 -- Determine if the next element in a list matches 0-to-n times due to an ellipsis
 macroElementMatchesMany :: LispVal -> Bool
@@ -555,11 +583,13 @@
 
 -- |This function walks the given block of code using the macro expansion algorithm,
 --  recursively expanding macro calls as they are encountered.
-expand :: Env       -- ^Environment of the code being expanded
-       -> Bool      -- ^True if the macro was defined within another macro
-       -> LispVal   -- ^Code to expand
-       -> IOThrowsError LispVal -- ^Expanded code
-expand env dim code = do
+expand :: 
+     Env       -- ^Environment of the code being expanded
+  -> Bool      -- ^True if the macro was defined within another macro
+  -> LispVal   -- ^Code to expand
+  -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Apply func
+  -> IOThrowsError LispVal -- ^Expanded code
+expand env dim code apply = do
   renameEnv <- liftIO $ nullEnv
   cleanupEnv <- liftIO $ nullEnv
 
@@ -570,24 +600,35 @@
 -- function parameter instead of the Syntax object
 --
 
-  walkExpanded env env env renameEnv cleanupEnv dim True False (List []) code
+  walkExpanded env env env renameEnv cleanupEnv dim True False (List []) code apply
 
 -- |Walk expanded code per Clinger's algorithm from Macros That Work
-walkExpanded :: Env -> Env -> Env -> Env -> Env -> Bool -> Bool -> Bool -> LispVal -> LispVal -> IOThrowsError LispVal
-walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (List l : ls)) = do
-  lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQuoted (List []) (List l)
-  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [lst]) (List ls)
+walkExpanded :: Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Bool 
+  -> Bool 
+  -> Bool 
+  -> LispVal 
+  -> LispVal 
+  -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Apply func
+  -> IOThrowsError LispVal
+walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (List l : ls)) apply = do
+  lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQuoted (List []) (List l) apply
+  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [lst]) (List ls) apply
 
-walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((Vector v) : vs)) = do
-  List lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List $ elems v)
-  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [asVector lst]) (List vs)
+walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((Vector v) : vs)) apply = do
+  List lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List $ elems v) apply
+  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [asVector lst]) (List vs) apply
 
-walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((DottedList ds d) : ts)) = do
-  List ls <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List ds)
-  l <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) d
-  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [DottedList ls l]) (List ts)
+walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((DottedList ds d) : ts)) apply = do
+  List ls <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List ds) apply
+  l <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) d apply
+  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [DottedList ls l]) (List ts) apply
 
-walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList inputIsQuoted (List result) (List (Atom aa : ts)) = do
+walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList inputIsQuoted (List result) (List (Atom aa : ts)) apply = do
   
  Atom a <- expandAtom renameEnv (Atom aa)
 
@@ -610,10 +651,9 @@
 --     || not startOfList
      || a == aa -- Prevent an infinite loop
      -- Preserve keywords encountered in the macro 
-     -- A complete hack I think. This will likely need to be revisited throughout the 3.4.x 
-     -- series of macro-related releases.
+     -- as each of these is really a special form, and renaming them
+     -- would not work because there is nothing to divert back...
      || a == "if"
-     || a == "begin"
      || a == "let-syntax" 
      || a == "letrec-syntax" 
      || a == "define-syntax" 
@@ -621,39 +661,40 @@
      || a == "set!"
      || a == "lambda"
     then walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv 
-                          dim startOfList inputIsQuoted (List result) a ts isQuoted isDefinedAsMacro
+                          dim startOfList inputIsQuoted (List result) a ts isQuoted isDefinedAsMacro apply
     else walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv 
-                      dim startOfList inputIsQuoted (List result) (List (Atom a : ts))
+                      dim startOfList inputIsQuoted (List result) (List (Atom a : ts)) apply
 
 
 -- Transform anything else as itself...
-walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (t : ts)) = do
-  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [t]) (List ts)
+walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (t : ts)) apply = do
+  walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [t]) (List ts) apply
 
 -- Base case - empty transform
-walkExpanded _ _ _ _ _ _ _ _ result@(List _) (List []) = return result
+walkExpanded _ _ _ _ _ _ _ _ result@(List _) (List []) _ = return result
 
 -- Single atom, rename (if necessary) and return
-walkExpanded _ _ _ renameEnv _ _ _ _ _ (Atom a) = expandAtom renameEnv (Atom a)
+walkExpanded _ _ _ renameEnv _ _ _ _ _ (Atom a) _ = expandAtom renameEnv (Atom a)
 
 -- If transforming into a scalar, just return the transform directly...
 -- Not sure if this is strictly desirable, but does not break any tests so we'll go with it for now.
-walkExpanded _ _ _ _ _ _ _ _ _ transform = return transform
+walkExpanded _ _ _ _ _ _ _ _ _ transform _ = return transform
 
 walkExpandedAtom :: Env 
-                 -> Env 
-                 -> Env 
-                 -> Env 
-                 -> Env 
-                 -> Bool 
-                 -> Bool 
-                 -> Bool 
-                 -> LispVal 
-                 -> String 
-                 -> [LispVal] 
-                 -> Bool -- is Quoted
-                 -> Bool -- is defined as macro
-                 -> IOThrowsError LispVal
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Bool 
+  -> Bool 
+  -> Bool 
+  -> LispVal 
+  -> String 
+  -> [LispVal] 
+  -> Bool -- is Quoted
+  -> Bool -- is defined as macro
+  -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Apply func
+  -> IOThrowsError LispVal
 
 {- 
 Some high-level design notes on how this could be made to work:
@@ -681,38 +722,47 @@
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True inputIsQuoted (List _)
     "let-syntax" 
     (List _bindings : _body)
-    False _ = do
+    False _ apply = do
         bodyEnv <- liftIO $ extendEnv useEnv []
         bodyRenameEnv <- liftIO $ extendEnv renameEnv []
         _ <- loadMacros useEnv bodyEnv (Just bodyRenameEnv) True _bindings
-        expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body)
+        expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body) apply
         return $ List [expanded]
 
-walkExpandedAtom _ _ _ _ _ _ True _ _ "let-syntax" ts False _ = do
+walkExpandedAtom _ _ _ _ _ _ True _ _ "let-syntax" ts False _ _ = do
   throwError $ BadSpecialForm "Malformed let-syntax expression" $ List (Atom "let-syntax" : ts)
 
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True inputIsQuoted (List _)
     "letrec-syntax" 
     (List _bindings : _body)
-    False _ = do
+    False _ apply = do
         bodyEnv <- liftIO $ extendEnv useEnv []
         bodyRenameEnv <- liftIO $ extendEnv renameEnv []
         _ <- loadMacros bodyEnv bodyEnv (Just bodyRenameEnv) True _bindings
-        expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body)
+        expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body) apply
         return $ List [expanded]
 
-walkExpandedAtom _ _ _ _ _ _ True _ _ "letrec-syntax" ts False _ = do
+walkExpandedAtom _ _ _ _ _ _ True _ _ "letrec-syntax" ts False _ _ = do
   throwError $ BadSpecialForm "Malformed letrec-syntax expression" $ List (Atom "letrec-syntax" : ts)
 
 walkExpandedAtom _ useEnv _ renameEnv _ _ True _ (List _)
     "define-syntax" 
     ([Atom keyword, (List (Atom "syntax-rules" : (List identifiers : rules)))])
-    False _ = do
+    False _ _ = do
         -- Do we need to rename the keyword, or at least take that into account?
         renameEnvClosure <- liftIO $ copyEnv renameEnv
         _ <- defineNamespacedVar useEnv macroNamespace keyword $ Syntax (Just useEnv) (Just renameEnvClosure) True identifiers rules
         return $ Nil "" -- Sentinal value
-walkExpandedAtom _ _ _ _ _ _ True _ _ "define-syntax" ts False _ = do
+walkExpandedAtom _ useEnv _ renameEnv _ _ True _ (List _)
+    "define-syntax" 
+    ([Atom keyword, 
+       (List [Atom "er-macro-transformer",  
+             (List (Atom "lambda" : List fparams : fbody))])])
+    False _ _ = do
+        f <- makeNormalFunc useEnv fparams fbody 
+        _ <- defineNamespacedVar useEnv macroNamespace keyword $ SyntaxExplicitRenaming f
+        return $ Nil "" -- Sentinal value
+walkExpandedAtom _ _ _ _ _ _ True _ _ "define-syntax" ts False _ _ = do
   throwError $ BadSpecialForm "Malformed define-syntax expression" $ List (Atom "define-syntax" : ts)
 
 
@@ -730,7 +780,7 @@
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
     "define" 
     [Atom var, val]
-    False _ = do
+    False _ apply = do
 {- It seems like this should be necessary, but it causes problems so it is
    disabled for now...
       isAlreadyRenamed <- liftIO $ isRecBound renameEnv var
@@ -739,15 +789,15 @@
           _ <- defineVar renameEnv var $ Atom var
           walk
 --        _ -> walk
- where walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "define", Atom var]) (List [val])
-walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"define" ts False _ = do
+ where walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "define", Atom var]) (List [val]) apply
+walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"define" ts False _ apply = do
     -- define is malformed, just transform as normal atom...
-    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts)
+    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
 
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
     "set!" 
     [Atom var, val]
-    False _ = do
+    False _ apply = do
       isLexicalDef <- liftIO $ isRecBound useEnv var
       isAlreadyRenamed <- liftIO $ isRecBound renameEnv var
       case (isLexicalDef, isAlreadyRenamed) of
@@ -759,31 +809,31 @@
            walk
         _ -> walk
   where
-    walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "set!"]) (List [Atom var, val])
+    walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "set!"]) (List [Atom var, val]) apply
 
-walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"set!" ts False _ = do
+walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"set!" ts False _ apply = do
     -- define is malformed, just transform as normal atom...
-    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts)
+    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
 
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
     "lambda" 
     (List vars : fbody)
-    False _ = do
+    False _ apply = do
 -- Placed here, the lambda primitive trumps a macro of the same name... (desired behavior?)
     -- Create a new Env for this, so args of the same name do not overwrite those in the current Env
 --    env <- liftIO $ extendEnv (trace ("found procedure abstraction, vars = " ++ show vars ++ "body = " ++ show fbody) renameEnv) []
     env <- liftIO $ extendEnv renameEnv []
     renamedVars <- markBoundIdentifiers env cleanupEnv vars []
-    walkExpanded defEnv useEnv divertEnv env cleanupEnv dim True False (List [Atom "lambda", (renamedVars)]) (List fbody)
+    walkExpanded defEnv useEnv divertEnv env cleanupEnv dim True False (List [Atom "lambda", (renamedVars)]) (List fbody) apply
 
-walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"lambda" ts False _ = do
+walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"lambda" ts False _ apply = do
     -- lambda is malformed, just transform as normal atom...
-    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts)
+    walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
 
-walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv _ True _ (List _)
+walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result)
     a
     ts 
-    False True = do
+    False True apply = do
     syn <- getNamespacedVar useEnv macroNamespace a
     case syn of
 --
@@ -807,10 +857,10 @@
          -- I am still concerned that this may highlight a flaw in the husk
          -- implementation, and that this solution may not be complete.
          --
-         List lexpanded <- cleanExpanded defEnv useEnv divertEnv renameEnv renameEnv True False False (List []) (List ts)
-         macroTransform defEnv useEnv divertEnv renameClosure cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : lexpanded))
+         List lexpanded <- cleanExpanded defEnv useEnv divertEnv renameEnv renameEnv True False False (List []) (List ts) apply
+         macroTransform defEnv useEnv divertEnv renameClosure cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : lexpanded)) apply
       Syntax (Just _defEnv) _ definedInMacro identifiers rules -> do 
-        macroTransform _defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts))
+        macroTransform _defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts)) apply
       Syntax Nothing _ definedInMacro identifiers rules -> do 
         -- A child renameEnv is not created because for a macro call there is no way an
         -- renamed identifier inserted by the macro could override one in the outer env.
@@ -818,28 +868,42 @@
         -- This is because the macro renames non-matched identifiers and stores mappings
         -- from the {rename ==> original}. Each new name is unique by definition, so
         -- no conflicts are possible.
-        macroTransform defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts))
+        macroTransform defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts)) apply
+      SyntaxExplicitRenaming transformer -> do
+        -- TODO: probably need to take macro hygiene, rename env, etc into account 
+
+-- TODO: unfortunately, since apply is required below, it means we need to thread that parameter
+-- through all our macro calls. it probably also means that expand will need to prompt for it as well
+        erRenameEnv <- liftIO $ nullEnv -- Local environment used just for this
+                                        -- Different than the syntax-rules rename env (??)
+        expanded <- explicitRenamingTransform 
+                      useEnv erRenameEnv (List (Atom a : ts)) transformer apply
+        walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv 
+          dim False False (List result) expanded apply
+
       _ -> throwError $ Default "Unexpected error processing a macro in walkExpandedAtom"
 
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim _ _ (List result)
     a
     ts
-    True _ = do
+    True _ apply = do
     let isQuasiQuoted = (a == "quasiquote")
     -- Cleanup all symbols in the quoted code
     List cleaned <- cleanExpanded 
                       defEnv useEnv divertEnv renameEnv cleanupEnv 
                       dim True isQuasiQuoted 
                       (List []) (List ts)
+                      apply
     return $ List $ result ++ (Atom a : cleaned)
 
 walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim _ _ (List result)
-    a ts isQuoted _ = do
+    a ts isQuoted _ apply = do
     walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv 
                  dim False isQuoted 
                 (List $ result ++ [Atom a]) (List ts)
+                 apply
 
-walkExpandedAtom _ _ _ _ _ _ _ _ _ _ _ _ _ = throwError $ Default "Unexpected error in walkExpandedAtom"
+walkExpandedAtom _ _ _ _ _ _ _ _ _ _ _ _ _ _ = throwError $ Default "Unexpected error in walkExpandedAtom"
 
 -- |Accept a list of bound identifiers from a lambda expression, and rename them
 --  Returns a list of the renamed identifiers as well as marking those identifiers
@@ -877,22 +941,34 @@
 --  ALSO, due to parent Env logic going on, these bindings need to be in some sort of
 --  'master' env that transcends those env's and maps all gensyms back to their original symbols
 --
-cleanExpanded :: Env -> Env -> Env -> Env -> Env -> Bool -> Bool -> Bool -> LispVal -> LispVal -> IOThrowsError LispVal
+cleanExpanded :: 
+     Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Env 
+  -> Bool 
+  -> Bool 
+  -> Bool 
+  -> LispVal 
+  -> LispVal 
+  -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Apply func
+  -> IOThrowsError LispVal
 
-cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List (List l : ls)) = do
-  lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List l)
-  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [lst]) (List ls)
+cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List (List l : ls)) apply = do
+  lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List l) apply
+  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [lst]) (List ls) apply
 
-cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List ((Vector v) : vs)) = do
-  List lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List $ elems v)
-  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [asVector lst]) (List vs)
+cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List ((Vector v) : vs)) apply = do
+  List lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List $ elems v) apply
+  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [asVector lst]) (List vs) apply
 
-cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List ((DottedList ds d) : ts)) = do
-  List ls <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List ds)
-  l <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) d
-  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [DottedList ls l]) (List ts)
+cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List ((DottedList ds d) : ts)) apply = do
+  List ls <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) (List ds) apply
+  l <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQQ (List []) d apply
+  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [DottedList ls l]) (List ts) apply
 
-cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList isQQ (List result) (List (Atom a : ts)) = do
+cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList isQQ (List result) (List (Atom a : ts)) apply = do
   expanded <- tmpexpandAtom cleanupEnv $ Atom a
   case (startOfList, isQQ, expanded) of
     -- Unquote an expression by continuing to expand it as a macro form
@@ -903,10 +979,10 @@
     --  - An "unquote" is found
     --
     (True, True, Atom "unquote") -> do 
-        r <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True False (List $ result ++ [Atom "unquote"]) (List ts)
+        r <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True False (List $ result ++ [Atom "unquote"]) (List ts) apply
         return r
     _ -> 
-        cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [expanded]) (List ts)
+        cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [expanded]) (List ts) apply
  where
   -- TODO: figure out a way to simplify this code (perhaps consolidate with expandAtom)
   tmpexpandAtom :: Env -> LispVal -> IOThrowsError LispVal
@@ -920,16 +996,16 @@
   tmpexpandAtom _ _a = return _a
 
 -- Transform anything else as itself...
-cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List (t : ts)) = do
-  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [t]) (List ts)
+cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQQ (List result) (List (t : ts)) apply = do
+  cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQQ (List $ result ++ [t]) (List ts) apply
 
 -- Base case - empty transform
-cleanExpanded _ _ _ _ _ _ _ _ result@(List _) (List []) = do
+cleanExpanded _ _ _ _ _ _ _ _ result@(List _) (List []) _ = do
   return result
 
 -- If transforming into a scalar, just return the transform directly...
 -- Not sure if this is strictly desirable, but does not break any tests so we'll go with it for now.
-cleanExpanded _ _ _ _ _ _ _ _ _ transform = return transform
+cleanExpanded _ _ _ _ _ _ _ _ _ transform _ = return transform
 
 
 {- |Transform input by walking the tranform structure and creating a new structure
@@ -1360,19 +1436,43 @@
            -> Bool      -- ^ True if the macro was defined inside another macro
            -> [LispVal] -- ^ List containing syntax-rule definitions
            -> IOThrowsError LispVal -- ^ A dummy value, unless an error is thrown
-loadMacros e be Nothing dim (List [Atom keyword, (List (Atom "syntax-rules" : (List identifiers : rules)))] : bs) = do
-  -- TODO: error checking
+
+-- Standard processing for a syntax-rules transformer
+loadMacros e be Nothing dim 
+    (List 
+        [Atom keyword, 
+         (List (Atom "syntax-rules" : 
+                (List identifiers : rules)))] : 
+        bs) = do
   _ <- defineNamespacedVar be macroNamespace keyword $ 
         Syntax (Just e) Nothing dim identifiers rules
   loadMacros e be Nothing dim bs
-loadMacros e be (Just re) dim args@(List [Atom keyword, (List (Atom syntaxrules : (List identifiers : rules)))] : bs) = do
+
+-- Standard processing for an explicit renaming transformer
+loadMacros e be Nothing dim 
+    (List  
+       [Atom keyword, (List [Atom "er-macro-transformer",  
+             (List (Atom "lambda" : List fparams : fbody))])]
+       : bs) = do
+  f <- makeNormalFunc e fparams fbody 
+  _ <- defineNamespacedVar be macroNamespace keyword $ SyntaxExplicitRenaming f
+  loadMacros e be Nothing dim bs
+
+-- This pattern is reached when there is a rename env, which
+-- means that we were already expanding a syntax-rules macro
+-- when loadMacros was called again.
+loadMacros e be (Just re) dim 
+    args@(List [Atom keyword, 
+                (List (Atom syntaxrules : spec))] : 
+               bs) = do
   Atom exKeyword <- expandAtom re (Atom keyword)
   exSynRules <- expandAtom re (Atom syntaxrules)
 
 -- TODO: need to process identifiers and rules - are they just expanded, or cleaned up?
 
-  case exSynRules of
-    Atom "syntax-rules" -> do
+  case (exSynRules, spec) of
+    (Atom "syntax-rules", 
+      (List identifiers : rules)) -> do
 --        -- Temporary hack to expand the rules
 --        List exRules <- cleanExpanded e e e re re dim False False (List []) (List rules)
 
@@ -1382,6 +1482,18 @@
 --             Syntax (Just e) (Just re) dim identifiers exRules --rules
              Syntax (Just e) (Just re) dim identifiers rules
         loadMacros e be (Just re) dim bs
-    _ -> throwError $ BadSpecialForm "Unable to evaluate form" $ List args
+    --
+    -- TODO: should check for lambda instead of _
+    --
+    (Atom "er-macro-transformer",
+      [List (Atom _ : List fparams : fbody)]) -> do
+
+        -- TODO: this is not good enough, er macros will
+        --       need access to the rename env
+        f <- makeNormalFunc e fparams fbody 
+        _ <- defineNamespacedVar be macroNamespace exKeyword $ SyntaxExplicitRenaming f
+        loadMacros e be (Just re) dim bs
+    _ -> throwError $ BadSpecialForm "Unable to evaluate form w/re" $ List args
+
 loadMacros _ _ _ _ [] = return $ Nil ""
 loadMacros _ _ _ _ form = throwError $ BadSpecialForm "Unable to evaluate form" $ List form 
diff --git a/hs-src/Language/Scheme/Macro/ExplicitRenaming.hs b/hs-src/Language/Scheme/Macro/ExplicitRenaming.hs
new file mode 100644
--- /dev/null
+++ b/hs-src/Language/Scheme/Macro/ExplicitRenaming.hs
@@ -0,0 +1,96 @@
+{- |
+Module      : Language.Scheme.Macro.ExplicitRenaming
+Copyright   : Justin Ethier
+Licence     : MIT (see LICENSE in the distribution)
+
+Maintainer  : github.com/justinethier
+Stability   : experimental
+Portability : portable
+
+This module contains code for explicit renaming (ER) macros, and is
+used by the Macro module to provide support for ER macros, both when 
+called directly or when ER macros are found during macro expansion. 
+This ensures both the er-macro-transformer and syntax-rules systems 
+are compatible with each other.
+
+Explicit renaming macros are based on the low-level facility from
+Will Clinger's paper "Hygienic Macros Through Explicit Renaming",
+which was developed to complement the high level specification
+language (syntax-rules) from "Macros that Work".
+
+-}
+
+module Language.Scheme.Macro.ExplicitRenaming
+    (
+      explicitRenamingTransform
+    ) where
+import Language.Scheme.Types
+import Language.Scheme.Variables
+import Language.Scheme.Primitives (_gensym)
+import Control.Monad.Error
+
+-- |Handle an explicit renaming macro
+explicitRenamingTransform :: 
+       Env -- ^Environment where macro was used
+    -> Env -- ^Temporary environment to store renamed variables
+    -> LispVal -- ^Form to transform
+    -> LispVal -- ^Macro transformer
+    -> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal) -- ^Eval func
+    -> IOThrowsError LispVal
+explicitRenamingTransform useEnv renameEnv lisp 
+                          transformer@(Func _ _ _ defEnv) apply = do
+  let continuation = makeNullContinuation useEnv
+  apply 
+    continuation
+    transformer
+    [lisp, 
+     IOFunc $ exRename useEnv renameEnv defEnv, 
+     IOFunc $ exCompare useEnv renameEnv defEnv] 
+
+-- |The explicit renaming "rename" function
+--
+-- From clinger's paper "Hygienic Macros Through Explicit Renaming":
+--
+-- The expression returned by the transformation procedure
+-- will be expanded in the syntactic environment obtained
+-- from the syntactic environment of the macro application
+-- by binding any fresh identifiers in the syntactic
+-- environment in which the macro was defined. This means
+-- that a renamed identifier will denote the same thing as
+-- the original identifier unless the transformation
+-- procedure that renamed the identifier placed an
+-- occurrence of it in a binding position.
+--
+-- The renaming procedure acts as a mathematical function
+-- in the sense that the idenfiers obtained from any two
+-- calls with the same argument will be the same in
+-- the sense of eqv?. It is an error if the renaming
+-- procedure is called after the transformation
+-- procedure has returned.
+exRename :: Env -> Env -> Env -> [LispVal] -> IOThrowsError LispVal
+exRename useEnv renameEnv defEnv [Atom a] = do
+  isDef <- liftIO $ isRecBound defEnv a
+  if isDef
+     then do
+       isRenamed <- liftIO $ isRecBound renameEnv a
+       if isRenamed
+          then do
+            renamed <- getVar renameEnv a
+            return renamed
+          else do
+            value <- getVar defEnv a
+            Atom renamed <- _gensym a -- Unique name
+            _ <- defineVar useEnv renamed value -- divert value to Use Env
+            _ <- defineVar renameEnv a $ Atom renamed -- Record renamed sym
+            return $ Atom renamed
+     else
+       return $ Atom a
+exRename _ _ _ form = throwError $ Default $ "Unable to rename: " ++ show form
+
+-- |The explicit renaming "compare" function
+exCompare :: Env -> Env -> Env -> [LispVal] -> IOThrowsError LispVal
+exCompare useEnv renameEnv defEnv values@[a, b] = do
+  return $ Bool $ eqVal a b
+exCompare _ _ _ form = throwError $ 
+   Default $ "Unable to compare: " ++ show form
+
diff --git a/hs-src/Language/Scheme/Primitives.hs b/hs-src/Language/Scheme/Primitives.hs
--- a/hs-src/Language/Scheme/Primitives.hs
+++ b/hs-src/Language/Scheme/Primitives.hs
@@ -54,6 +54,15 @@
  , symbol2String 
  , string2Symbol
  --data Unpacker = forall a . Eq a => AnyUnpacker (LispVal -> ThrowsError a)
+
+ -- ** Character
+ , charCIBoolBinop 
+ , charPredicate
+ , charUpper
+ , charLower
+ , char2Int
+ , int2Char
+
  -- ** Predicate
  , isHashTbl
  , isChar 
@@ -71,6 +80,7 @@
  , boolBinop 
  , unaryOp 
  , strBoolBinop 
+ , charBoolBinop 
  , boolBoolBinop
  , unpackStr 
  , unpackBool
@@ -115,6 +125,7 @@
 -- I/O Primitives
 -- These primitives all execute within the IO monad
 ---------------------------------------------------
+
 makePort :: IOMode -> [LispVal] -> IOThrowsError LispVal
 makePort mode [String filename] = liftM Port $ liftIO $ openFile filename mode
 makePort _ [] = throwError $ NumArgs 1 []
@@ -425,6 +436,11 @@
 stringCIBoolBinop _ [badType] = throwError $ TypeMismatch "string string" badType
 stringCIBoolBinop _ badArgList = throwError $ NumArgs 2 badArgList
 
+charCIBoolBinop :: (Char -> Char -> Bool) -> [LispVal] -> ThrowsError LispVal
+charCIBoolBinop op [(Char s1), (Char s2)] = boolBinop unpackChar op [(Char $ toLower s1), (Char $ toLower s2)]
+charCIBoolBinop _ [badType] = throwError $ TypeMismatch "character character" badType
+charCIBoolBinop _ badArgList = throwError $ NumArgs 2 badArgList
+
 stringAppend :: [LispVal] -> ThrowsError LispVal
 stringAppend [(String s)] = return $ String s -- Needed for "last" string value
 stringAppend (String st : sts) = do
@@ -516,6 +532,27 @@
 string2Symbol [notString] = throwError $ TypeMismatch "string" notString
 string2Symbol args@(_ : _) = throwError $ NumArgs 1 args
 
+charUpper :: [LispVal] -> ThrowsError LispVal
+charUpper [Char c] = return $ Char $ toUpper c
+charUpper [notChar] = throwError $ TypeMismatch "char" notChar
+
+charLower :: [LispVal] -> ThrowsError LispVal
+charLower [Char c] = return $ Char $ toLower c
+charLower [notChar] = throwError $ TypeMismatch "char" notChar
+
+char2Int :: [LispVal] -> ThrowsError LispVal
+char2Int [Char c] = return $ Number $ toInteger $ ord c 
+char2Int [notChar] = throwError $ TypeMismatch "char" notChar
+
+int2Char :: [LispVal] -> ThrowsError LispVal
+int2Char [Number n] = return $ Char $ chr $ fromInteger n 
+int2Char [notInt] = throwError $ TypeMismatch "integer" notInt
+
+-- |Determine if given character satisfies the given predicate
+charPredicate :: (Char -> Bool) -> [LispVal] -> ThrowsError LispVal
+charPredicate pred ([Char c]) = return $ Bool $ pred c 
+charPredicate _ _ = return $ Bool False
+
 isChar :: [LispVal] -> ThrowsError LispVal
 isChar ([Char _]) = return $ Bool True
 isChar _ = return $ Bool False
@@ -555,8 +592,13 @@
 numBoolBinop = boolBinop unpackNum -}
 strBoolBinop :: (String -> String -> Bool) -> [LispVal] -> ThrowsError LispVal
 strBoolBinop = boolBinop unpackStr
+charBoolBinop = boolBinop unpackChar
 boolBoolBinop :: (Bool -> Bool -> Bool) -> [LispVal] -> ThrowsError LispVal
 boolBoolBinop = boolBinop unpackBool
+
+unpackChar :: LispVal -> ThrowsError Char
+unpackChar (Char c) = return c
+unpackChar notChar = throwError $ TypeMismatch "character" notChar
 
 unpackStr :: LispVal -> ThrowsError String
 unpackStr (String s) = return s
diff --git a/hs-src/Language/Scheme/Types.hs b/hs-src/Language/Scheme/Types.hs
--- a/hs-src/Language/Scheme/Types.hs
+++ b/hs-src/Language/Scheme/Types.hs
@@ -218,6 +218,8 @@
      --   application. In any case, it is convenient to define the type here 
      --   because syntax objects are stored in the same environments and 
      --   manipulated by the same functions as regular variables.
+ | SyntaxExplicitRenaming LispVal
+   -- ^ Syntax for an explicit-renaming macro
  | EOF
  | Nil String
  -- ^Internal use only; do not use this type directly.
@@ -368,6 +370,7 @@
 showVal (PrimitiveFunc _) = "<primitive>"
 showVal (Continuation _ _ _ _ _) = "<continuation>"
 showVal (Syntax _ _ _ _ _) = "<syntax>"
+showVal (SyntaxExplicitRenaming _) = "<er-macro-transformer syntax>"
 showVal (Func {params = args, vararg = varargs, body = _, closure = _}) =
   "(lambda (" ++ unwords (map show args) ++
     (case varargs of
diff --git a/husk-scheme.cabal b/husk-scheme.cabal
--- a/husk-scheme.cabal
+++ b/husk-scheme.cabal
@@ -1,5 +1,5 @@
 Name:                husk-scheme
-Version:             3.5.6
+Version:             3.5.7
 Synopsis:            R5RS Scheme interpreter, compiler, and library.
 Description:         A dialect of R5RS Scheme written in Haskell. Provides advanced 
                      features including continuations, hygienic macros, a Haskell FFI,
@@ -15,6 +15,7 @@
 Tested-with:         GHC == 7.2.2, GHC == 7.0.2, GHC == 6.12.3, GHC == 6.10.4
 
 Extra-Source-Files:  README.markdown
+                     ChangeLog.markdown
                      LICENSE
                      AUTHORS
 Data-Files:          stdlib.scm srfi/srfi-1.scm srfi/srfi-55.scm
@@ -28,7 +29,7 @@
     default: True
 
 Library
-  Build-Depends:   base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc-paths
+  Build-Depends:   base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory
   Extensions:      ExistentialQuantification
   Hs-Source-Dirs:  hs-src
   Exposed-Modules: Language.Scheme.Core
@@ -38,19 +39,20 @@
                    Language.Scheme.Plugins.CPUTime
 -- Other-Modules:
                    Language.Scheme.Macro
+                   Language.Scheme.Macro.ExplicitRenaming
                    Language.Scheme.Macro.Matches
                    Language.Scheme.Numerical
                    Language.Scheme.Parser
                    Language.Scheme.Primitives
   if flag(useffi)
-    Build-Depends: ghc
+    Build-Depends: ghc, ghc-paths
     Exposed-Modules:  Language.Scheme.FFI
     cpp-options: -DUseFfi
 
 Executable         huski
-  Build-Depends:   husk-scheme, base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc-paths
+  Build-Depends:   husk-scheme, base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory
   if flag(useffi)
-    Build-Depends: ghc
+    Build-Depends: ghc, ghc-paths
     cpp-options: -DUseFfi
   Extensions:      ExistentialQuantification
   Main-is:         shell.hs
@@ -59,7 +61,7 @@
 Executable huskc
   Build-Depends: husk-scheme, base >= 2.0 && < 5, array, containers, haskeline, transformers, mtl, parsec, directory, ghc-paths, process, filepath
   if flag(useffi)
-    Build-Depends: ghc
+    Build-Depends: ghc, ghc-paths
     cpp-options: -DUseFfi
   Extensions:      ExistentialQuantification
   Main-is: huskc.hs
diff --git a/stdlib.scm b/stdlib.scm
--- a/stdlib.scm
+++ b/stdlib.scm
@@ -43,6 +43,8 @@
 (define (list . objs)  objs)
 (define (id obj)       obj)
 
+; TODO: this is not flipping args. not part of R5RS, but 
+;       as it is now, what is the point?
 (define (flip func)    (lambda (arg1 arg2) (func arg1 arg2)))
 
 (define (curry func arg1)  (lambda (arg) (apply func (cons arg1 (list arg)))))
