packages feed

husk-scheme 3.10 → 3.11

raw patch · 17 files changed

+1347/−360 lines, 17 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Language.Scheme.Compiler: AstAssignM :: String -> HaskAST -> HaskAST
- Language.Scheme.Compiler: AstContinuation :: String -> String -> HaskAST
- Language.Scheme.Compiler: AstFunction :: String -> String -> [HaskAST] -> HaskAST
- Language.Scheme.Compiler: AstValue :: String -> HaskAST
- Language.Scheme.Compiler: CompileOptions :: String -> Bool -> Bool -> Maybe String -> CompOpts
- Language.Scheme.Compiler: _collectLiterals :: [LispVal] -> [LispVal] -> Bool -> (Maybe [LispVal])
- Language.Scheme.Compiler: ast2Str :: LispVal -> String
- Language.Scheme.Compiler: astcArgs :: HaskAST -> String
- Language.Scheme.Compiler: astcNext :: HaskAST -> String
- Language.Scheme.Compiler: astfArgs :: HaskAST -> String
- Language.Scheme.Compiler: astfCode :: HaskAST -> [HaskAST]
- Language.Scheme.Compiler: astfName :: HaskAST -> String
- Language.Scheme.Compiler: asts2Str :: [LispVal] -> String
- Language.Scheme.Compiler: collectLiterals :: [LispVal] -> (Maybe [LispVal])
- Language.Scheme.Compiler: collectLiteralsAndVars :: [LispVal] -> (Maybe [LispVal])
- Language.Scheme.Compiler: coptsNextFunc :: CompOpts -> Maybe String
- Language.Scheme.Compiler: coptsThisFunc :: CompOpts -> String
- Language.Scheme.Compiler: coptsThisFuncUseArgs :: CompOpts -> Bool
- Language.Scheme.Compiler: coptsThisFuncUseValue :: CompOpts -> Bool
- Language.Scheme.Compiler: createAstCont :: CompOpts -> String -> String -> HaskAST
- Language.Scheme.Compiler: createAstFunc :: CompOpts -> [HaskAST] -> HaskAST
- Language.Scheme.Compiler: data CompOpts
- Language.Scheme.Compiler: data HaskAST
- Language.Scheme.Compiler: defaultCompileOptions :: String -> CompOpts
- Language.Scheme.Compiler: header :: String -> Bool -> [String]
- Language.Scheme.Compiler: headerComment :: [String]
- Language.Scheme.Compiler: headerImports :: [String]
- Language.Scheme.Compiler: headerModule :: [String]
- Language.Scheme.Compiler: instance Show HaskAST
- Language.Scheme.Compiler: joinL :: [[a]] -> [a] -> [a]
- Language.Scheme.Compiler: showValAST :: HaskAST -> String
+ Language.Scheme.Compiler: defineTopLevelVars :: Env -> [LispVal] -> IOThrowsError LispVal
+ Language.Scheme.Compiler.Libraries: importAll :: Env -> Env -> [LispVal] -> CompLibOpts -> CompOpts -> IOThrowsError [HaskAST]
+ Language.Scheme.Compiler.Types: AstAssignM :: String -> HaskAST -> HaskAST
+ Language.Scheme.Compiler.Types: AstContinuation :: String -> String -> HaskAST
+ Language.Scheme.Compiler.Types: AstFunction :: String -> String -> [HaskAST] -> HaskAST
+ Language.Scheme.Compiler.Types: AstValue :: String -> HaskAST
+ Language.Scheme.Compiler.Types: CompileLibraryOptions :: (String -> Maybe String -> Env -> [HaskAST] -> [LispVal] -> IOThrowsError [HaskAST]) -> (Env -> String -> String -> Maybe String -> IOThrowsError [HaskAST]) -> CompLibOpts
+ Language.Scheme.Compiler.Types: CompileOptions :: String -> Bool -> Bool -> Maybe String -> CompOpts
+ Language.Scheme.Compiler.Types: ast2Str :: LispVal -> String
+ Language.Scheme.Compiler.Types: astcArgs :: HaskAST -> String
+ Language.Scheme.Compiler.Types: astcNext :: HaskAST -> String
+ Language.Scheme.Compiler.Types: astfArgs :: HaskAST -> String
+ Language.Scheme.Compiler.Types: astfCode :: HaskAST -> [HaskAST]
+ Language.Scheme.Compiler.Types: astfName :: HaskAST -> String
+ Language.Scheme.Compiler.Types: asts2Str :: [LispVal] -> String
+ Language.Scheme.Compiler.Types: compBlock :: CompLibOpts -> String -> Maybe String -> Env -> [HaskAST] -> [LispVal] -> IOThrowsError [HaskAST]
+ Language.Scheme.Compiler.Types: compLisp :: CompLibOpts -> Env -> String -> String -> Maybe String -> IOThrowsError [HaskAST]
+ Language.Scheme.Compiler.Types: createAstCont :: CompOpts -> String -> String -> HaskAST
+ Language.Scheme.Compiler.Types: createAstFunc :: CompOpts -> [HaskAST] -> HaskAST
+ Language.Scheme.Compiler.Types: data CompLibOpts
+ Language.Scheme.Compiler.Types: data CompOpts
+ Language.Scheme.Compiler.Types: data HaskAST
+ Language.Scheme.Compiler.Types: defaultCompileOptions :: String -> CompOpts
+ Language.Scheme.Compiler.Types: header :: String -> Bool -> [String]
+ Language.Scheme.Compiler.Types: headerComment :: [String]
+ Language.Scheme.Compiler.Types: headerImports :: [String]
+ Language.Scheme.Compiler.Types: headerModule :: [String]
+ Language.Scheme.Compiler.Types: instance Show HaskAST
+ Language.Scheme.Compiler.Types: joinL :: [[a]] -> [a] -> [a]
+ Language.Scheme.Compiler.Types: moduleRuntimeVar :: [Char]
+ Language.Scheme.Compiler.Types: showValAST :: HaskAST -> String
+ Language.Scheme.Core: findFileOrLib :: [Char] -> ErrorT LispError IO String
+ Language.Scheme.Core: meval :: Env -> LispVal -> LispVal -> IOThrowsError LispVal
+ Language.Scheme.Core: nullEnvWithImport :: IO Env
+ Language.Scheme.Core: r5rsEnv' :: IO Env
+ Language.Scheme.Types: nullLisp :: LispVal
+ Language.Scheme.Variables: recPrintEnv :: Env -> IO String

Files

ChangeLog.markdown view
@@ -1,3 +1,19 @@++v3.11+--------++The major change in this release is support for R<sup>7</sup>RS style library syntax in the compiler. This enables functionality that was previously only available in the interpreter, and sets the stage for husk to begin adding support for R<sup>7</sup>RS.++API changes:++- The Compiler Haskell API has been reorganized to use a Types module, and a new Libraries module has been added to store code for libraries.++Bug fixes:++- Allow the husk compiler to reference variables that are defined later in the program. For example, the following now compiles: `(define (foo) (bar))` `(define (bar) (foo))`+- Fixed `string-set!` to allow an expression to be passed as the character argument.+- Fixed `string-ref` to work when the string argument is passed using a variable.+ v3.10 -------- 
README.markdown view
@@ -1,6 +1,6 @@ [<img src="https://github.com/justinethier/husk-scheme/raw/master/docs/husk-scheme.png" alt="husk-scheme">](http://justinethier.github.com/husk-scheme) -husk is a dialect of Scheme written in Haskell that adheres to the [R<sup>5</sup>RS standard](http://www.schemers.org/Documents/Standards/R5RS/HTML/). Advanced R<sup>5</sup>RS features are provided including continuations, hygienic macros, and a full numeric tower.+husk is a dialect of Scheme written in Haskell that implements a superset of the [R<sup>5</sup>RS standard](http://www.schemers.org/Documents/Standards/R5RS/HTML/). Advanced R<sup>5</sup>RS features are provided including continuations, hygienic macros, and a full numeric tower.  husk may be used as either a stand-alone interpreter or as an extension language within a larger Haskell application. By closely following the R<sup>5</sup>RS standard, the intent is to develop a Scheme that is as compatible as possible with other R<sup>5</sup>RS Schemes. husk is mature enough for use in production applications, however it is not optimized for performance-critical applications.  
hs-src/Compiler/huskc.hs view
@@ -4,15 +4,15 @@ Licence     : MIT (see LICENSE in the distribution)  Maintainer  : github.com/justinethier-Stability   : experimental Portability : portable -A front-end for an experimental compiler+A front-end for the husk compiler -}  module Main where import Paths_husk_scheme import Language.Scheme.Compiler+import Language.Scheme.Compiler.Types import qualified Language.Scheme.Core import Language.Scheme.Types     -- Scheme data types import Language.Scheme.Variables -- Scheme variable operations@@ -27,13 +27,6 @@ main :: IO () main = do  -  putStrLn ""-  putStrLn "!!! This version of huskc is Experimental !!!"-  putStrLn ""-  putStrLn "You might want to consult the issue list before use:"-  putStrLn "https://github.com/justinethier/husk-scheme/issues"-  putStrLn ""-   -- Read command line args and process options   args <- getArgs   let (actions, nonOpts, msgs) = getOpt Permute options args@@ -141,7 +134,7 @@ -- TODO: how to integrate r5rsEnv and libraries?  -  env <- Language.Scheme.Core.r5rsEnv+  env <- Language.Scheme.Core.r5rsEnv'   stdlib <- getDataFileName "lib/stdlib.scm"   srfi55 <- getDataFileName "lib/srfi/srfi-55.scm" -- (require-extension) @@ -163,15 +156,19 @@         Just _ -> True         _ -> False -  (String nextFunc, libsC, libSrfi55C) <- case stdlib of-    Nothing -> return (String "run", [], [])+  -- TODO: clean this up later+  --moduleFile <- liftIO $ getDataFileName "lib/modules.scm"++  (String nextFunc, libsC, libSrfi55C, libModules) <- case stdlib of+    Nothing -> return (String "run", [], [], [])     Just stdlib' -> do       -- TODO: it is only temporary to compile the standard library each time. It should be        --       precompiled and just added during the ghc compilation       libsC <- compileLisp env stdlib' "run" (Just "exec55")-      libSrfi55C <- compileLisp env srfi55 "exec55" (Just "exec55_2")+      libSrfi55C <- compileLisp env srfi55 "exec55" (Just "exec55_3")+      --libModules <- compileLisp env moduleFile "exec55_2" (Just "exec55_3")       liftIO $ Language.Scheme.Core.registerExtensions env getDataFileName-      return (String "exec", libsC, libSrfi55C)+      return (String "exec", libsC, libSrfi55C, []) --libModules)    -- Initialize the compiler module and begin   _ <- initializeCompiler env@@ -193,6 +190,8 @@       _ <- hPutStrLn outH " ------ END OF STDLIB ------"       _ <- writeList outH $ map show libSrfi55C       hPutStrLn outH " ------ END OF SRFI 55 ------"+      -- _ <- writeList outH $ map show libModules+      hPutStrLn outH " ------ END OF MODULES ------"     False -> do       hPutStrLn outH "exec _ _ _ _ = return $ Nil \"\"" -- Placeholder   _ <- liftIO $ writeList outH $ map show execC
hs-src/Language/Scheme/Compiler.hs view
@@ -7,22 +7,53 @@ Stability   : experimental Portability : portable -This module contains an experimental Scheme to Haskell compiler. --The compiler performs the following transformations:+This module contains a Scheme to Haskell compiler which performs the following +transformations:  > Scheme AST (LispVal) => Haskell AST (HaskAST) => Compiled Code (String) -The GHC compiler is then used to create a native executable.+The GHC compiler is then used to create a native executable. At present, the +focus has just been on creating a compiler that will generate correct, working +code. Many optimizations could and need to be made for time and space... -At present, the focus has just been on creating a compiler that will-generate correct, working code. Many optimizations could and need to-be made for time and space...+Note the following type is used for all functions generated by the compiler:  +> compiledFunc :: +>   Env ->                  -- Runtime Environment+>   LispVal ->              -- Continuation+>   LispVal ->              -- Value+>   Maybe [LispVal] ->      -- Additional arguments+>   IOThrowsError LispVal   -- Result+ -} -module Language.Scheme.Compiler where -import qualified Language.Scheme.Core (apply, evalLisp, version)+module Language.Scheme.Compiler +    (+      compile+    , compileApply+    , compileBlock+    , compileDivertedVars +    , compileExpr+    , compileLambdaList+    , compileLisp+    , compileScalar+    , compileSpecialForm+    , compileSpecialFormBody+    , compileSpecialFormEntryPoint+    , defineLambdaVars+    , defineTopLevelVars+    , divertVars +    , initializeCompiler+    , isPrim+    , mcompile+    , mfunc+    )+where +import Language.Scheme.Compiler.Libraries as LSCL+import Language.Scheme.Compiler.Types+import qualified Language.Scheme.Core as LSC +    (apply, evalLisp, evalString, findFileOrLib, meval, nullEnvWithImport, +     primitiveBindings, r5rsEnv, version)  import qualified Language.Scheme.Macro import Language.Scheme.Primitives import Language.Scheme.Types@@ -38,176 +69,6 @@ import Data.Word -- 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-data CompOpts = CompileOptions {-    coptsThisFunc :: String,-    coptsThisFuncUseValue :: Bool,-    coptsThisFuncUseArgs :: Bool,-    coptsNextFunc :: Maybe String-    }--defaultCompileOptions :: String -> CompOpts-defaultCompileOptions thisFunc = CompileOptions thisFunc False False Nothing---- |Create code for a function-createAstFunc -  :: CompOpts  -- ^ Compilation options-  -> [HaskAST] -- ^ Body of the function-  -> HaskAST -- ^ Complete function code-createAstFunc (CompileOptions thisFunc useVal useArgs _) funcBody = do-  let val = case useVal of-              True -> "value"-              _ -> "_"-      args = case useArgs of-               True -> "(Just args)"-               _ -> "_"-  AstFunction thisFunc (" env cont " ++ val ++ " " ++ args ++ " ") funcBody---- |Create code for a continutation-createAstCont -  :: CompOpts -- ^ Compilation options-  -> String -- ^ Value to send to the continuation-  -> String -- ^ Extra leading indentation (or blank string if none)-  -> HaskAST -- ^ Generated code-createAstCont (CompileOptions _ _ _ (Just nextFunc)) var indentation = do-  AstValue $ indentation ++ "  continueEval env (makeCPS env cont " ++ nextFunc ++ ") " ++ var-createAstCont (CompileOptions _ _ _ Nothing) var indentation = do-  AstValue $ indentation ++ "  continueEval env cont " ++ var---- |A very basic type to store a Haskell AST.---  FUTURE: is this even necessary? Would just a string be good enough?-data HaskAST = AstAssignM String HaskAST-  | AstFunction {astfName :: String,---                 astfType :: String,-                 astfArgs :: String,-                 astfCode :: [HaskAST]-                } - | AstValue String- | AstContinuation {astcNext :: String,-                    astcArgs :: String-                   }--showValAST :: HaskAST -> String-showValAST (AstAssignM var val) = "  " ++ var ++ " <- " ++ show val-showValAST (AstFunction name args code) = do-  let fheader = "\n" ++ name ++ args ++ " = do "-  let fbody = unwords . map (\x -> "\n" ++ x ) $ map showValAST code-  fheader ++ fbody -showValAST (AstValue v) = v--showValAST (AstContinuation nextFunc args) =-    "  continueEval env (makeCPSWArgs env cont " ++ -       nextFunc ++ " " ++ args ++ ") $ Nil \"\""--instance Show HaskAST where show = showValAST---- |A utility function to join list members together-joinL -  :: forall a. [[a]] -- ^ Original list-of-lists-  -> [a] -- ^ Separator -  -> [a] -- ^ Joined list-joinL ls sep = concat $ Data.List.intersperse sep ls---- |Convert abstract syntax tree to a string-ast2Str :: LispVal -> String -ast2Str (String s) = "String " ++ show s-ast2Str (Char c) = "Char " ++ show c-ast2Str (Atom a) = "Atom " ++ show a-ast2Str (Number n) = "Number (" ++ show n ++ ")"-ast2Str (Complex c) = "Complex $ (" ++ (show $ realPart c) ++ ") :+ (" ++ (show $ imagPart c) ++ ")"-ast2Str (Rational r) = "Rational $ (" ++ (show $ numerator r) ++ ") % (" ++ (show $ denominator r) ++ ")"-ast2Str (Float f) = "Float (" ++ show f ++ ")"-ast2Str (Bool True) = "Bool True"-ast2Str (Bool False) = "Bool False"-ast2Str (HashTable ht) = do- let ls = Data.Map.toList ht -     conv (a, b) = "(" ++ ast2Str a ++ "," ++ ast2Str b ++ ")"- "HashTable $ Data.Map.fromList $ [" ++ joinL (map conv ls) "," ++ "]"-ast2Str (Vector v) = do-  let ls = Data.Array.elems v-      size = (length ls) - 1-  "Vector (listArray (0, " ++ show size ++ ")" ++ "[" ++ joinL (map ast2Str ls) "," ++ "])"-ast2Str (ByteVector bv) = do-  let ls = BS.unpack bv-  "ByteVector ( BS.pack " ++ "[" ++ joinL (map show ls) "," ++ "])"-ast2Str (List ls) = "List [" ++ joinL (map ast2Str ls) "," ++ "]"-ast2Str (DottedList ls l) = -  "DottedList [" ++ joinL (map ast2Str ls) "," ++ "] $ " ++ ast2Str l---- |Convert a list of abstract syntax trees to a list of strings-asts2Str :: [LispVal] -> String-asts2Str ls = do-    "[" ++ (joinL (map ast2Str ls) ",") ++ "]"--headerComment, headerModule, headerImports :: [String]-headerComment = [-   "--"- , "-- This file was automatically generated by the husk scheme compiler,"- , "-- huskc version " ++ Language.Scheme.Core.version- , "--"]--headerModule = ["module Main where "]-headerImports = [-   "Language.Scheme.Core "- , "Language.Scheme.Numerical "- , "Language.Scheme.Primitives "- , "Language.Scheme.Types     -- Scheme data types "- , "Language.Scheme.Variables -- Scheme variable operations "- , "Control.Monad.Error "- , "Data.Array "- , " qualified Data.ByteString as BS "- , "Data.Complex "- , " qualified Data.Map "- , "Data.Ratio "- , "Data.Word "- , "System.IO "]--header :: String -> Bool -> [String]-header filepath useCompiledLibs = do-  let env = if useCompiledLibs-            then "primitiveBindings"-            else "r5rsEnv"-  [ " "-    , "-- |Get variable at runtime "-    , "getRTVar env var = do " -    , "  v <- getVar env var " -    , "  return $ case v of "-    , "    List _ -> Pointer var env "-    , "    DottedList _ _ -> Pointer var env "-    , "    String _ -> Pointer var env "-    , "    Vector _ -> Pointer var env "-    , "    ByteVector _ -> Pointer var env "-    , "    HashTable _ -> Pointer var env "-    , "    _ -> v "-    , " "-    , "applyWrapper env cont (Nil _) (Just (a:as))  = do "-    , "  apply cont a as "-    , " "-    , "applyWrapper env cont value (Just (a:as))  = do "-    , "  apply cont a $ as ++ [value] "-    , " "-    , "getDataFileName' :: FilePath -> IO FilePath "-    , "getDataFileName' name = return $ \"" ++ (Language.Scheme.Util.escapeBackslashes filepath) ++ "\" ++ name "-    , " "-    , "exec55_2 env cont _ _ = do "-    , "  liftIO $ registerExtensions env getDataFileName' "-    , "  continueEval env (makeCPS env cont exec) (Nil \"\")"-    , " "-    , "main :: IO () "-    , "main = do "-    , "  env <- " ++ env ++ " "-    , "  result <- (runIOThrows $ liftM show $ run env (makeNullContinuation env) (Nil \"\") Nothing) "-    , "  case result of "-    , "    Just errMsg -> putStrLn errMsg "-    , "    _ -> return () "-    , " "]---- NOTE: the following type is used for all functions generated by the compiler: --- , "run :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal "-- -- Define imports var here as an empty list. -- This list is appended to by (load-ffi) instances, -- and the imports are explicitly added later on...@@ -218,20 +79,30 @@   compileLisp :: Env -> String -> String -> Maybe String -> IOThrowsError [HaskAST]-compileLisp env filename entryPoint exitPoint = load filename >>= compileBlock entryPoint exitPoint env []+compileLisp env filename entryPoint exitPoint = do+    filename' <- LSC.findFileOrLib filename +    load filename' >>= compileBlock entryPoint exitPoint env [] -- compileBlock -- -- Note: Uses explicit recursion to transform a block of code, because --  later lines may depend on previous ones-compileBlock :: String -> Maybe String -> Env -> [HaskAST] -> [LispVal] -> IOThrowsError [HaskAST]-compileBlock symThisFunc symLastFunc env result [c] = do+compileBlock :: String -> Maybe String -> Env -> [HaskAST] -> [LispVal] +             -> IOThrowsError [HaskAST]+compileBlock symThisFunc symLastFunc env result lisps = do+  _ <- defineTopLevelVars env lisps+  _compileBlock symThisFunc symLastFunc env result lisps++_compileBlock :: String -> Maybe String -> Env -> [HaskAST] -> [LispVal] +              -> IOThrowsError [HaskAST]+_compileBlock symThisFunc symLastFunc env result [c] = do   compiled <- mcompile env c $ CompileOptions symThisFunc False False symLastFunc    return $ result ++ compiled-compileBlock symThisFunc symLastFunc env result (c:cs) = do+_compileBlock symThisFunc symLastFunc env result (c:cs) = do   Atom symNextFunc <- _gensym "f"-  compiled <- mcompile env c $ CompileOptions symThisFunc False False (Just symNextFunc)-  compileBlock symNextFunc symLastFunc env (result ++ compiled) cs-compileBlock _ _ _ result [] = return result+  compiled <- mcompile env c $ +                       CompileOptions symThisFunc False False (Just symNextFunc)+  _compileBlock symNextFunc symLastFunc env (result ++ compiled) cs+_compileBlock _ _ _ result [] = return result  -- TODO: could everything just be regular function calls except when a continuation is 'added to the stack' via a makeCPS(makeCPSWArgs ...) ?? I think this could be made more efficient @@ -247,17 +118,51 @@   serialized <- mapM serialize l    return $ "[" ++ concat (Data.List.intersperse "," serialized) ++ "]"  where serialize (Atom a) = return $ (show a)-       serialize a = throwError $ Default $ "invalid parameter to lambda list: " ++ show a+       serialize a = throwError $ Default $ +                         "invalid parameter to lambda list: " ++ show a  -- |Add lambda variables to the compiler's environment defineLambdaVars :: Env -> [LispVal] -> IOThrowsError LispVal defineLambdaVars env (Atom v : vs) = do-    _ <- defineVar env v $ Number 0 -- For now it is good enough to define it, actual value does not matter+    _ <- defineVar env v $ Number 0 -- For now, actual value does not matter     defineLambdaVars env vs defineLambdaVars env (_ : vs) = defineLambdaVars env vs defineLambdaVars env [] = return $ Nil "" +-- |Find all variables defined at "this" level and load their symbols into+--  the environment. This allows the compiler validation to work even +--  though a variable is used in a sub-form before it is defined further+--  on down in the program+defineTopLevelVars :: Env -> [LispVal] -> IOThrowsError LispVal+defineTopLevelVars env (List [Atom "define", Atom var, form] : ls) = do+    _ <- defineTopLevelVar env var+    defineTopLevelVars env ls+defineTopLevelVars env ((List (Atom "define" : List (Atom var : _) : _)) : ls) = do+    _ <- defineTopLevelVar env var+    defineTopLevelVars env ls+defineTopLevelVars env ((List (Atom "define" : DottedList (Atom var : _) _ : _)) : ls) = do+    _ <- defineTopLevelVar env var+    defineTopLevelVars env ls+defineTopLevelVars env (_ : ls) = defineTopLevelVars env ls+defineTopLevelVars _ _ = return nullLisp ++defineTopLevelVar env var = do+  defineVar env var $ Number 0 -- Actual value not loaded at the moment ++-- |Compile a Lisp expression to Haskell. Note this function does+--  not expand macros; mcompile should be used instead if macros+--  may appear in the expression. compile :: Env -> LispVal -> CompOpts -> IOThrowsError [HaskAST]+-- Experimenting with r7rs library support+compile env +        ast@(List (Atom "import" : mods)) +        copts@(CompileOptions thisFunc _ _ lastFunc) = do+    LispEnv meta <- getVar env "*meta-env*"+    LSCL.importAll env +                   meta +                   mods +                  (CompileLibraryOptions compileBlock compileLisp) +                   copts compile _ (Nil n) copts = compileScalar ("  return $ Nil " ++ (show n)) copts compile _ (String s) copts = compileScalar ("  return $ String " ++ (show s)) copts compile _ (Char c) copts = compileScalar ("  return $ Char " ++ (show c)) copts@@ -278,11 +183,12 @@                createAstCont copts "val" ""]    False -> throwError $ UnboundVar "Variable is not defined" a -compile _ (List [Atom "quote", val]) copts = compileScalar (" return $ " ++ ast2Str val) copts+compile _ (List [Atom "quote", val]) copts = +  compileScalar (" return $ " ++ ast2Str val) copts  compile env ast@(List [Atom "expand",  _body]) copts = do   compileSpecialFormBody env ast copts (\ _ -> do-    val <- Language.Scheme.Macro.expand env False _body Language.Scheme.Core.apply+    val <- Language.Scheme.Macro.expand env False _body LSC.apply     compileScalar (" return $ " ++ ast2Str val) copts)  compile env ast@(List (Atom "let-syntax" : List _bindings : _body)) copts = do@@ -290,7 +196,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) Language.Scheme.Core.apply+    expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) LSC.apply     divertVars bodyEnv expanded copts compexp)  where       -- Pick up execution here after expansion@@ -304,7 +210,7 @@     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) Language.Scheme.Core.apply+    expanded <- Language.Scheme.Macro.expand bodyEnv False (List _body) LSC.apply     divertVars bodyEnv expanded copts compexp)   where       -- Pick up execution here after expansion@@ -313,6 +219,29 @@          List e -> compile bodyEnv' (List $ Atom "begin" : e) copts'          e -> compile bodyEnv' e copts' +-- A non-standard way to rebind a macro to another keyword+compile env +        ast@(List [Atom "define-syntax", +                   Atom newKeyword,+                   Atom keyword]) +        copts = do+  bound <- getNamespacedVar' env macroNamespace keyword+  case bound of+    Just m -> do+        defineNamespacedVar env macroNamespace newKeyword m+        compFunc <- return $ [+          AstValue $ "  bound <- getNamespacedVar' env macroNamespace \"" ++ +                          keyword ++ "\"",+          AstValue $ "  case bound of ",+          AstValue $ "    Just m -> ",+          AstValue $ "      defineNamespacedVar env macroNamespace \"" ++ +                              newKeyword ++ "\" m",+          AstValue $ "    Nothing -> throwError $ TypeMismatch \"macro\" $ " ++ +                             "Atom \"" ++ keyword ++ "\"",+          createAstCont copts "(Nil \"\")" ""]+        return $ [createAstFunc copts compFunc]+    Nothing -> throwError $ TypeMismatch "macro" $ Atom keyword+ compile env ast@(List [Atom "define-syntax", Atom keyword,   (List [Atom "er-macro-transformer",      (List (Atom "lambda" : List fparams : fbody))])])@@ -326,7 +255,8 @@        compFunc <- return $ [       AstValue $ "  f <- makeNormalFunc env " ++ fparamsStr ++ " " ++ fbodyStr, -      AstValue $ "  defineNamespacedVar env macroNamespace \"" ++ keyword ++ "\" $ SyntaxExplicitRenaming f",+      AstValue $ "  defineNamespacedVar env macroNamespace \"" ++ keyword ++ +                      "\" $ SyntaxExplicitRenaming f",       createAstCont copts "(Nil \"\")" ""]     return $ [createAstFunc copts compFunc]) @@ -372,7 +302,8 @@        AstValue $ "    _ -> " ++ symConsequence ++ " env cont (Nil \"\") [] "]          -- Join compiled code together-    return $ [createAstFunc copts f] ++ compPredicate ++ [compCheckPredicate] ++ compConsequence ++ compAlternate)+    return $ [createAstFunc copts f] ++ compPredicate ++ [compCheckPredicate] ++ +              compConsequence ++ compAlternate)  compile env ast@(List [Atom "set!", Atom var, form]) copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do@@ -380,14 +311,7 @@     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...-    _ <- defineVar env var form -- TODO: setVar (per above comment)+    _ <- setVar env var form      entryPt <- compileSpecialFormEntryPoint "set!" symDefine copts     compDefine <- compileExpr env form symDefine $ Just symMakeDefine@@ -398,11 +322,13 @@  compile env ast@(List [Atom "set!", nonvar, _]) copts = do    compileSpecialFormBody env ast copts (\ nextFunc -> do-    f <- compileSpecialForm "set!" ("throwError $ TypeMismatch \"variable\" $ String \"" ++ (show nonvar) ++ "\"")  copts+    f <- compileSpecialForm "set!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts     return [f]) compile env ast@(List (Atom "set!" : args)) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do-    f <- compileSpecialForm "set!" ("throwError $ NumArgs 2 $ [String \"" ++ (show args) ++ "\"]") copts -- TODO: Cheesy to use a string, but fine for now...+    f <- compileSpecialForm "set!" ("throwError $ NumArgs 2 $ [String \"" ++ +            (show args) ++ "\"]") copts -- Cheesy to use a string, but fine for now...     return [f])  compile env ast@(List [Atom "define", Atom var, form]) copts@(CompileOptions _ _ _ _) = do@@ -432,7 +358,8 @@        createAstCont copts "result" ""]     return $ [createAstFunc copts f] ++ compDefine ++ [compMakeDefine]) -compile env ast@(List (Atom "define" : List (Atom var : fparams) : fbody)) copts@(CompileOptions _ _ _ _) = do+compile env ast@(List (Atom "define" : List (Atom var : fparams) : fbody)) +        copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     bodyEnv <- liftIO $ extendEnv env []     -- bind lambda params in the extended env@@ -443,19 +370,22 @@     compiledBody <- compileBlock symCallfunc Nothing bodyEnv [] fbody         -- Cache macro expansions within function body-    ebody <- mapM (\ lisp -> Language.Scheme.Macro.macroEval env lisp Language.Scheme.Core.apply) fbody+    ebody <- mapM (\ lisp -> Language.Scheme.Macro.macroEval env lisp LSC.apply) fbody     -- Store var in huskc's env for macro processing (and same for other vers of define)     _ <- makeNormalFunc env fparams ebody >>= defineVar env var         -- Entry point; ensure var is not rebound     f <- return $ [-          AstValue $ "  result <- makeNormalHFunc env (" ++ compiledParams ++ ") " ++ symCallfunc,+          AstValue $ "  result <- makeNormalHFunc env (" ++ compiledParams ++ +                     ") " ++ symCallfunc,           AstValue $ "  _ <- defineVar env \"" ++ var ++ "\" result ",           createAstCont copts "result" ""           ]     return $ [createAstFunc copts f] ++ compiledBody) -compile env ast@(List (Atom "define" : DottedList (Atom var : fparams) varargs : fbody)) copts@(CompileOptions _ _ _ _) = do+compile env +        ast@(List (Atom "define" : DottedList (Atom var : fparams) varargs : fbody)) +        copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     bodyEnv <- liftIO $ extendEnv env []     -- bind lambda params in the extended env@@ -466,18 +396,19 @@     compiledBody <- compileBlock symCallfunc Nothing bodyEnv [] fbody         -- Store var in huskc's env for macro processing (and same for other vers of define)-    ebody <- mapM (\ lisp -> Language.Scheme.Macro.macroEval env lisp Language.Scheme.Core.apply) fbody+    ebody <- mapM (\ lisp -> Language.Scheme.Macro.macroEval env lisp LSC.apply) fbody     _ <- makeVarargs varargs env fparams ebody >>= defineVar env var         -- Entry point; ensure var is not rebound     f <- return $ [-          AstValue $ "  result <- makeHVarargs (" ++ ast2Str varargs ++ ") env (" ++ compiledParams ++ ") " ++ symCallfunc,-          AstValue $ "  _ <- defineVar env \"" ++ var ++ "\" result ",-          createAstCont copts "result" ""-          ]+      AstValue $ "  result <- makeHVarargs (" ++ ast2Str varargs ++ ") env (" ++ +                       compiledParams ++ ") " ++ symCallfunc,+      AstValue $ "  _ <- defineVar env \"" ++ var ++ "\" result ",+      createAstCont copts "result" "" ]     return $ [createAstFunc copts f] ++ compiledBody) -compile env ast@(List (Atom "lambda" : List fparams : fbody)) copts@(CompileOptions _ _ _ _) = do+compile env ast@(List (Atom "lambda" : List fparams : fbody)) +        copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symCallfunc <- _gensym "lambdaFuncEntryPt"     compiledParams <- compileLambdaList fparams@@ -489,15 +420,15 @@     compiledBody <- compileBlock symCallfunc Nothing bodyEnv [] fbody         -- Entry point; ensure var is not rebound-   -- TODO: will probably end up creating a common function for this,-   --       since it is almost the same as in "if"     f <- return $ [-          AstValue $ "  result <- makeNormalHFunc env (" ++ compiledParams ++ ") " ++ symCallfunc,+          AstValue $ "  result <- makeNormalHFunc env (" ++ compiledParams ++ +                     ") " ++ symCallfunc,           createAstCont copts "result" ""           ]     return $ [createAstFunc copts f] ++ compiledBody) -compile env ast@(List (Atom "lambda" : DottedList fparams varargs : fbody)) copts@(CompileOptions _ _ _ _) = do+compile env ast@(List (Atom "lambda" : DottedList fparams varargs : fbody)) +        copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symCallfunc <- _gensym "lambdaFuncEntryPt"     compiledParams <- compileLambdaList fparams@@ -510,12 +441,13 @@         -- Entry point; ensure var is not rebound     f <- return $ [-          AstValue $ "  result <- makeHVarargs (" ++ ast2Str varargs ++ ") env (" ++ compiledParams ++ ") " ++ symCallfunc,-          createAstCont copts "result" ""-          ]+      AstValue $ "  result <- makeHVarargs (" ++ ast2Str varargs ++ ") env (" ++ +         compiledParams ++ ") " ++ symCallfunc,+      createAstCont copts "result" "" ]     return $ [createAstFunc copts f] ++ compiledBody) -compile env ast@(List (Atom "lambda" : varargs@(Atom _) : fbody)) copts@(CompileOptions _ _ _ _) = do+compile env ast@(List (Atom "lambda" : varargs@(Atom _) : fbody)) +        copts@(CompileOptions _ _ _ _) = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symCallfunc <- _gensym "lambdaFuncEntryPt"    @@ -536,21 +468,33 @@   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symDefine <- _gensym "stringSetFunc"     Atom symMakeDefine <- _gensym "stringSetFuncMakeSet"+    Atom symChr <- _gensym "stringSetChar"+    Atom symCompiledI <- _gensym "stringI"    -    entryPt <- compileSpecialFormEntryPoint "string-set!" symDefine copts-    compDefine <- compileExpr env i symDefine $ Just symMakeDefine-    compMakeDefine <- return $ AstFunction symMakeDefine " env cont idx _ " [+    entryPt <- compileSpecialFormEntryPoint "string-set!" symChr copts+    compChr <- compileExpr env character symChr $ Just symDefine+    compDefine <- return $ AstFunction symDefine " env cont chr _ " [+        AstValue $ "  " ++ symCompiledI ++ " env (makeCPSWArgs env cont " ++ +          symMakeDefine ++ " [chr]) (Nil \"\") Nothing " ]+    compI <- compileExpr env i symCompiledI Nothing+    compMakeDefine <- return $ AstFunction symMakeDefine " env cont idx (Just [chr]) " [        AstValue $ "  tmp <- getVar env \"" ++ var ++ "\"",        AstValue $ "  derefValue <- recDerefPtrs tmp",-       -- TODO: not entirely correct below; should compile the character argument rather-       --       than directly inserting it into the compiled code...-       AstValue $ "  result <- substr (derefValue, (" ++ ast2Str(character) ++ "), idx)",+       AstValue $ "  result <- substr (derefValue, chr, idx)",        AstValue $ "  _ <- updateObject env \"" ++ var ++ "\" result",        createAstCont copts "result" ""]-    return $ [entryPt] ++ compDefine ++ [compMakeDefine])+    return $ [entryPt, compDefine, compMakeDefine] ++ compI ++ compChr) --- TODO: eval env cont args@(List [Atom "string-set!" , nonvar , _ , _ ]) = do--- TODO: eval env cont fargs@(List (Atom "string-set!" : args)) = do +compile env ast@(List [Atom "string-set!", nonvar, _, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "string-set!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "string-set!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "string-set!" ("throwError $ NumArgs 3 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])  compile env ast@(List [Atom "set-car!", Atom var, argObj]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do@@ -576,22 +520,23 @@     -- Compiled version of argObj     compiledObj <- compileExpr env argObj symCompiledObj Nothing     -    -- Function to check looked-up var and call into appropriate handlers; based on code from Core+    -- Function to check looked-up var and call into appropriate handlers; +    -- based on code from Core     ---    -- This is so verbose because we need to have overloads of symObj to deal with many possible inputs.+    -- This is so verbose because we need to have overloads of symObj to +    -- deal with many possible inputs.     -- FUTURE: consider making these functions part of the runtime.     compObj <- return $ AstValue $ "" ++-                 symObj ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" ++-                 symObj ++ " _ _ obj@(List []) _ = throwError $ TypeMismatch \"pair\" obj\n" ++-   -- TODO: below, we want to make sure obj is of the right type. if so, compile obj and call into the "set" -   --       function below to do the actual set-car-                 symObj ++ " e c obj@(List (_ : _)) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" ++-                 symObj ++ " e c obj@(DottedList _ _) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" ++-                 symObj ++ " _ _ obj _ = throwError $ TypeMismatch \"pair\" obj\n"+      symObj ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" +++      symObj ++ " _ _ obj@(List []) _ = throwError $ TypeMismatch \"pair\" obj\n" +++      symObj ++ " e c obj@(List (_ : _)) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" +++      symObj ++ " e c obj@(DottedList _ _) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" +++      symObj ++ " _ _ obj _ = throwError $ TypeMismatch \"pair\" obj\n"         -- Function to do the actual (set!), based on code from Core     ---    -- This is so verbose because we need to have overloads of symObj to deal with many possible inputs.+    -- This is so verbose because we need to have overloads of symObj to deal +    -- with many possible inputs.     -- FUTURE: consider making these functions part of the runtime.     compDoSet <- return $ AstValue $ "" ++                  symDoSet ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" ++@@ -602,8 +547,16 @@     -- Return a list of all the compiled code     return $ [entryPt, compGetVar, compObj, compDoSet] ++ compiledObj) --- TODO: eval env cont args@(List [Atom "set-car!" , nonvar , _ ]) = do--- TODO: eval env cont fargs@(List (Atom "set-car!" : args)) = do+compile env ast@(List [Atom "set-car!", nonvar, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "set-car!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "set-car!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "set-car!" ("throwError $ NumArgs 2 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])  compile env ast@(List [Atom "set-cdr!", Atom var, argObj]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do@@ -634,35 +587,46 @@     -- This is so verbose because we need to have overloads of symObj to deal with many possible inputs.     -- FUTURE: consider making these functions part of the runtime.     compObj <- return $ AstValue $ "" ++-                 symObj ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" ++-                 symObj ++ " _ _ obj@(List []) _ = throwError $ TypeMismatch \"pair\" obj\n" ++-   -- TODO: below, we want to make sure obj is of the right type. if so, compile obj and call into the "set" +      symObj ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" +++      symObj ++ " _ _ obj@(List []) _ = throwError $ TypeMismatch \"pair\" obj\n" +++   -- TODO: below, we want to make sure obj is of the right type. if so, +   -- compile obj and call into the "set"     --       function below to do the actual set-car-                 symObj ++ " e c obj@(List (_ : _)) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" ++-                 symObj ++ " e c obj@(DottedList _ _) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" ++-                 symObj ++ " _ _ obj _ = throwError $ TypeMismatch \"pair\" obj\n"+      symObj ++ " e c obj@(List (_ : _)) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" +++      symObj ++ " e c obj@(DottedList _ _) _ = " ++ symCompiledObj ++ " e (makeCPSWArgs e c " ++ symDoSet ++ " [obj]) (Nil \"\") Nothing\n" +++      symObj ++ " _ _ obj _ = throwError $ TypeMismatch \"pair\" obj\n"         -- Function to do the actual (set!), based on code from Core     ---    -- This is so verbose because we need to have overloads of symObj to deal with many possible inputs.+    -- This is so verbose because we need to have overloads of symObj +    -- to deal with many possible inputs.     -- FUTURE: consider making these functions part of the runtime.     compDoSet <- return $ AstValue $ "" ++-                 symDoSet ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" ++-                 symDoSet ++ " e c obj (Just [List (l : _)]) = do\n" ++-                             "   l' <- recDerefPtrs l\n" ++-                             "   obj' <- recDerefPtrs obj\n" ++-                             "   (cons [l', obj']) >>= updateObject e \"" ++ var ++ "\" >>= " ++ finalContinuation ++-                 symDoSet ++ " e c obj (Just [DottedList (l : _) _]) = do\n" ++-                             "   l' <- recDerefPtrs l\n" ++-                             "   obj' <- recDerefPtrs obj\n" ++-                             "   (cons [l', obj']) >>= updateObject e \"" ++ var ++ "\" >>= " ++ finalContinuation ++-                 symDoSet ++ " _ _ _ _ = throwError $ InternalError \"Unexpected argument to " ++ symDoSet ++ "\"\n"+      symDoSet ++ " :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal\n" +++      symDoSet ++ " e c obj (Just [List (l : _)]) = do\n" +++                  "   l' <- recDerefPtrs l\n" +++                  "   obj' <- recDerefPtrs obj\n" +++                  "   (cons [l', obj']) >>= updateObject e \"" ++ var ++ "\" >>= " ++ finalContinuation +++      symDoSet ++ " e c obj (Just [DottedList (l : _) _]) = do\n" +++                  "   l' <- recDerefPtrs l\n" +++                  "   obj' <- recDerefPtrs obj\n" +++                  "   (cons [l', obj']) >>= updateObject e \"" ++ var ++ "\" >>= " ++ finalContinuation +++      symDoSet ++ " _ _ _ _ = throwError $ InternalError \"Unexpected argument to " ++ symDoSet ++ "\"\n"         -- Return a list of all the compiled code     return $ [entryPt, compGetVar, compObj, compDoSet] ++ compiledObj) --- TODO: eval env cont args@(List [Atom "set-cdr!" , nonvar , _ ]) = do--- TODO: eval env cont fargs@(List (Atom "set-cdr!" : args)) = do+compile env ast@(List [Atom "set-cdr!", nonvar, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "set-cdr!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "set-cdr!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "set-cdr!" ("throwError $ NumArgs 2 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])+ compile env ast@(List [Atom "vector-set!", Atom var, i, object]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symCompiledIdx <- _gensym "vectorSetIdx"@@ -685,9 +649,18 @@         return $ [entryPt, compiledIdxWrapper, compiledUpdate] ++ compiledIdx ++ compiledObj) --- TODO: eval env cont args@(List [Atom "vector-set!" , nonvar , _ , _]) = do --- TODO: eval env cont fargs@(List (Atom "vector-set!" : args)) = do +compile env ast@(List [Atom "vector-set!", nonvar, _, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "vector-set!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "vector-set!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "vector-set!" ("throwError $ NumArgs 3 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f]) + compile env ast@(List [Atom "bytevector-u8-set!", Atom var, i, object]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     Atom symCompiledIdx <- _gensym "bytevectorSetIdx"@@ -710,8 +683,16 @@         return $ [entryPt, compiledIdxWrapper, compiledUpdate] ++ compiledIdx ++ compiledObj) --- TODO: eval env cont args@(List [Atom "bytevector-u8-set!" , nonvar , _ , _]) = do --- TODO: eval env cont fargs@(List (Atom "bytevector-u8-set!" : args)) = do +compile env ast@(List [Atom "bytevector-u8-set!", nonvar, _, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "bytevector-u8-set!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "bytevector-u8-set!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "bytevector-u8-set!" ("throwError $ NumArgs 3 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])  compile env ast@(List [Atom "hash-table-set!", Atom var, rkey, rvalue]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do@@ -737,8 +718,16 @@         return $ [entryPt, compiledIdxWrapper, compiledUpdate] ++ compiledIdx ++ compiledObj) --- TODO: eval env cont args@(List [Atom "hash-table-set!" , nonvar , _ , _]) = do--- TODO: eval env cont fargs@(List (Atom "hash-table-set!" : args)) = do+compile env ast@(List [Atom "hash-table-set!", nonvar, _, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "hash-table-set!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "hash-table-set!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "hash-table-set!" ("throwError $ NumArgs 3 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])  compile env ast@(List [Atom "hash-table-delete!", Atom var, rkey]) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do@@ -758,8 +747,18 @@        createAstCont copts "result" ""]         return $ [entryPt, compiledUpdate] ++ compiledIdx)--- TODO: eval env cont fargs@(List (Atom "hash-table-delete!" : args)) = do +compile env ast@(List [Atom "hash-table-delete!", nonvar, _]) copts = do +  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "hash-table-delete!" ("throwError $ TypeMismatch \"variable\"" +++                            " $ String \"" ++ (show nonvar) ++ "\"")  copts+    return [f])+compile env ast@(List (Atom "hash-table-delete!" : args)) copts = do+  compileSpecialFormBody env ast copts (\ nextFunc -> do+    f <- compileSpecialForm "hash-table-delete!" ("throwError $ NumArgs 2 $ [String \"" ++ +            (show args) ++ "\"]") copts+    return [f])+ compile env ast@(List (Atom "%import" : args)) copts = do   compileSpecialFormBody env ast copts (\ nextFunc -> do     throwError $ NotImplemented $ "%import, with args: " ++ show args)@@ -771,8 +770,7 @@   -- Explicitly do NOT call compileSpecialFormBody here, since load is not normally a special form    -- F*ck it, just run the evaluator here since filename is req'd at compile time-  --String filename' <- Language.Scheme.Core.evalLisp env filename-  fname <- Language.Scheme.Core.evalLisp env filename+  fname <- LSC.evalLisp env filename   case fname of     -- Compile contents of the file     String fn -> compileFile fn@@ -812,12 +810,13 @@  compile env (List [Atom "load", filename]) copts = do -- TODO: allow filename from a var, support env optional arg  -- TODO: error handling for string below- String filename' <- Language.Scheme.Core.evalLisp env filename+ String filename' <- LSC.evalLisp env filename  Atom symEntryPt <- _gensym "load"  result <- compileLisp env filename' symEntryPt Nothing  return $ result ++     [createAstFunc copts [-    AstValue $ "  result <- " ++ symEntryPt ++ " env (makeNullContinuation env) (Nil \"\") Nothing",+    AstValue $ "  result <- " ++ symEntryPt ++ +               " env (makeNullContinuation env) (Nil \"\") Nothing",     createAstCont copts "result" ""]]  -- FUTURE: eventually it should be possible to evaluate the args instead of assuming@@ -831,7 +830,8 @@   -- Only append module again if it is not already in the list   List l <- getNamespacedVar env 't' {-"internal"-} "imports"   _ <- if not ((String moduleName) `elem` l)-          then setNamespacedVar env 't' {-"internal"-} "imports" $ List $ l ++ [String moduleName]+          then setNamespacedVar env 't' {-"internal"-} "imports" $ +                                List $ l ++ [String moduleName]           else return $ String ""    -- Pass along moduleName as another top-level import@@ -844,11 +844,18 @@ compile env args@(List (_ : _)) copts = mfunc env args compileApply copts  compile _ badForm _ = throwError $ BadSpecialForm "Unrecognized special form" badForm +-- |Expand macros and compile the resulting code mcompile :: Env -> LispVal -> CompOpts -> IOThrowsError [HaskAST] mcompile env lisp copts = mfunc env lisp compile copts-mfunc :: Env -> LispVal -> (Env -> LispVal -> CompOpts -> IOThrowsError [HaskAST]) -> CompOpts -> IOThrowsError [HaskAST] ++-- |Expand macros and then pass control to the given function +mfunc :: Env+      -> LispVal +      -> (Env -> LispVal -> CompOpts -> IOThrowsError [HaskAST]) +      -> CompOpts +      -> IOThrowsError [HaskAST]  mfunc env lisp func copts = do-  expanded <- Language.Scheme.Macro.macroEval env lisp Language.Scheme.Core.apply+  expanded <- Language.Scheme.Macro.macroEval env lisp LSC.apply   divertVars env expanded copts func  -- |Do the actual insertion of diverted variables back to the @@ -907,7 +914,10 @@  -- |A wrapper for each special form that allows the form variable  --  (EG: "if") to be redefined at compile time-compileSpecialFormBody env ast@(List (Atom fnc : args)) copts@(CompileOptions _ _ _ nextFunc) spForm = do+compileSpecialFormBody env +                       ast@(List (Atom fnc : args)) +                       copts@(CompileOptions _ _ _ nextFunc) +                       spForm = do   isDefined <- liftIO $ isRecBound env fnc   case isDefined of     True -> mfunc env ast compileApply copts @@ -935,7 +945,7 @@      -- Primitive (non-I/O) function with literal args,       -- evaluate at compile time      (Just primFunc, Just ls, _) -> do-       result <- Language.Scheme.Core.apply +       result <- LSC.apply          (makeNullContinuation env)         primFunc         ls@@ -982,7 +992,8 @@      c <- return $        AstFunction coptsThis " env cont _ _ " [-        AstValue $ "  continueEval env (makeCPS env (makeCPS env cont " ++ nextFunc ++ ") " ++ stubFunc ++ ") $ Nil\"\""]  +        AstValue $ "  continueEval env (makeCPS env (makeCPS env cont " ++ +                   nextFunc ++ ") " ++ stubFunc ++ ") $ Nil\"\""]       _comp <- mcompile env func $ CompileOptions stubFunc False False Nothing      -- Haskell variables must be used to retrieve each atom from the env@@ -994,10 +1005,13 @@     rest <- case coptsNext of              Nothing -> return $ [                AstFunction nextFunc-                " env cont value _ " $ varLines ++ [AstValue $ "  apply cont value " ++ args]]+                " env cont value _ " $ varLines ++ +                [AstValue $ "  apply cont value " ++ args]]              Just fnextExpr -> return $ [                AstFunction nextFunc -                " env cont value _ " $ varLines ++ [AstValue $ "  apply (makeCPS env cont " ++ fnextExpr ++ ") value " ++ args]]+                " env cont value _ " $ varLines ++ +                [AstValue $ "  apply (makeCPS env cont " ++ +                            fnextExpr ++ ") value " ++ args]]     return $ [c] ++ _comp ++ rest    -- |Compile function and args as a chain of continuations@@ -1008,11 +1022,13 @@      c <- return $        AstFunction coptsThis " env cont _ _ " [-        AstValue $ "  continueEval env (makeCPS env (makeCPS env cont " ++ wrapperFunc ++ ") " ++ stubFunc ++ ") $ Nil\"\""]  +        AstValue $ "  continueEval env (makeCPS env (makeCPS env cont " ++ +                   wrapperFunc ++ ") " ++ stubFunc ++ ") $ Nil\"\""]       -- Use wrapper to pass high-order function (func) as an argument to apply     wrapper <- return $        AstFunction wrapperFunc " env cont value _ " [-          AstValue $ "  continueEval env (makeCPSWArgs env cont " ++ nextFunc ++ " [value]) $ Nil \"\""]+          AstValue $ "  continueEval env (makeCPSWArgs env cont " ++ +                     nextFunc ++ " [value]) $ Nil \"\""]     _comp <- mcompile env func $ CompileOptions stubFunc False False Nothing      rest <- case fparams of
+ hs-src/Language/Scheme/Compiler/Libraries.hs view
@@ -0,0 +1,329 @@+{- |+Module      : Language.Scheme.Compiler.Libraries+Copyright   : Justin Ethier+Licence     : MIT (see LICENSE in the distribution)++Maintainer  : github.com/justinethier+Stability   : experimental+Portability : portable++This module contains support for compiling libraries of scheme code.++-}++module Language.Scheme.Compiler.Libraries+    ( +      importAll+    )+where +import Language.Scheme.Compiler.Types+import qualified Language.Scheme.Core as LSC +    (evalLisp, findFileOrLib, meval, nullEnvWithImport)+import Language.Scheme.Primitives+import Language.Scheme.Types+import Language.Scheme.Variables+import Control.Monad.Error++-- |Import all given modules and generate code for them+importAll +    :: Env +    -- ^ Compilation environment+    -> Env +    -- ^ Compilation meta environment, containing code from modules.scm+    -> [LispVal]+    -- ^ Modules to import+    -> CompLibOpts+    -- ^ Misc options required by compiler library functions+    -> CompOpts+    -- ^ Misc options required by compiler functions+    -> IOThrowsError [HaskAST]+    -- ^ Compiled code+importAll env metaEnv [m] lopts +          copts@(CompileOptions thisFunc _ _ lastFunc) = do+    _importAll env metaEnv m lopts copts+importAll env metaEnv (m : ms) lopts+          copts@(CompileOptions thisFunc _ _ lastFunc) = do+    Atom nextFunc <- _gensym "importAll"+    c <- _importAll env metaEnv m lopts $ +                    CompileOptions thisFunc False False (Just nextFunc)+    rest <- importAll env metaEnv ms lopts $+                      CompileOptions nextFunc False False lastFunc+    stub <- case rest of +        [] -> return [createFunctionStub nextFunc lastFunc]+        _ -> return []+    return $ c ++ rest ++ stub+importAll _ _ [] _ _ = return []++_importAll env metaEnv m lopts copts = do+    -- Resolve import+    resolved <- LSC.evalLisp metaEnv $ +         List [Atom  "resolve-import", List [Atom "quote", m]]+    case resolved of+        List (moduleName : imports) -> do+            importModule env metaEnv moduleName imports lopts copts+        DottedList [List moduleName] imports@(Bool False) -> do+            importModule env metaEnv (List moduleName) [imports] lopts copts+        err -> throwError $ TypeMismatch "module/import" err++-- |Import a single module+importModule env metaEnv moduleName imports lopts +             copts@(CompileOptions thisFunc _ _ lastFunc) = do+    Atom symImport <- _gensym "importFnc"++    -- Load module+    code <- loadModule metaEnv moduleName lopts $ +              CompileOptions thisFunc False False (Just symImport)+    +    -- Get module env, and import module env into env+    LispEnv modEnv <- LSC.evalLisp metaEnv $ +       List [Atom "module-env", List [Atom "find-module", List [Atom "quote", moduleName]]]+    _ <- eval env $ List [Atom "%import", +                          LispEnv env, +                          LispEnv modEnv, +                          List [Atom "quote", List imports], +                          Bool False]+    +    importFunc <- return $ [+        -- fromEnv is a LispEnv passed in as the 'value' parameter.+        -- But the source of 'value' is different depending on the +        -- context, so we call into this function to figure it out+        codeToGetFromEnv moduleName code,+        AstValue $ "  _ <- evalLisp env $ List [Atom \"%import\", LispEnv env, value, List [Atom \"quote\", " ++ +                  (ast2Str $ List imports) ++ "], Bool False]",+        createAstCont (CompileOptions symImport False False lastFunc) "(value)" ""]+    +    -- thisFunc MUST be defined, so include a stub if there was nothing to import+    stub <- case code of+        [] -> return [createFunctionStub thisFunc (Just symImport)]+        _ -> return []++    return $ [createAstFunc (CompileOptions symImport True False lastFunc) +                             importFunc] ++ code ++ stub+ where +  --+  -- The import's "from" env can come from many places; this function+  -- figures that out and creates a new 'value' if necessary to send+  -- the proper value to %import in the above code+  --+  codeToGetFromEnv (List [Atom "scheme", Atom "r5rs"]) _ = do+     -- This is a hack to compile-in a full environment for the (scheme r5rs) import.+     --+     -- TODO: This really should be handled by the add-module! that is executed during+     --  module initialization, instead of having a special case here+     AstValue $ "  r5 <- liftIO $ r5rsEnv\n  let value = LispEnv r5"++  codeToGetFromEnv name [] = do+     -- No code was generated because module was loaded previously, so retrieve+     -- it from runtime memory+     AstValue $ "  value <- evalLisp env $ List [Atom \"hash-table-ref\", Atom \"" ++ +                moduleRuntimeVar ++ "\", List [Atom \"quote\", " ++ +               (ast2Str name) ++ "]]" ++  codeToGetFromEnv _ _ = AstValue $ ""++-- | Load module into memory and generate compiled code+loadModule+    :: Env +    -- ^ Compilation meta environment, containing code from modules.scm+    -> LispVal+    -- ^ Name of the module to load+    -> CompLibOpts+    -- ^ Misc options required by compiler library functions+    -> CompOpts+    -- ^ Misc options required by compiler functions+    -> IOThrowsError [HaskAST]+    -- ^ Compiled code, or an empty list if the module was already compiled+    --   and loaded into memory+loadModule metaEnv name lopts copts@(CompileOptions thisFunc _ _ lastFunc) = do+    -- Get the module definition, or load it from file if necessary+    mod' <- eval metaEnv $ List [Atom "find-module", List [Atom "quote", name]]+    case mod' of+        Bool False -> return [] -- Even possible to reach this line?+        _ -> do+             mod <- recDerefPtrs mod'+             modEnv <- LSC.evalLisp metaEnv $ List [Atom "module-env", mod]+             case modEnv of+                Bool False -> do+                {-------------------------------------------+                    Control flow for compiled code:++                     - create new env+                     - call into func directly to load it+                     - return new env and save to memory+                     - continue on to lastFunc+                --------------------------------------------}+                    Atom symStartLoadNewEnv <- _gensym "startLoadingNewEnvFnc"+                    Atom symEndLoadNewEnv <- _gensym "doneLoadingNewEnvFnc"++                    newEnvFunc <- return $ [+                        AstValue $ "  newEnv <- liftIO $ nullEnvWithImport",+                        AstValue $ "  _ <- defineVar newEnv \"" ++ moduleRuntimeVar ++ +                                       "\" $ Pointer \"" ++ moduleRuntimeVar ++ "\" env",+                        AstValue $ "  _ <- " ++ symStartLoadNewEnv ++ +                                   " newEnv (makeNullContinuation newEnv) (LispEnv env) []",+                        -- Save loaded module into runtime memory in case+                        -- it gets included somewhere else later on+                        AstValue $ "  _ <- evalLisp env $ List [Atom \"hash-table-set!\", Atom \"" ++ +                                   moduleRuntimeVar ++ "\", List [Atom \"quote\", " +++                                  (ast2Str name) ++ "], LispEnv newEnv]",+                        createAstCont copts "(LispEnv newEnv)" ""]+                    +                    -- Create new env for module, per eval-module+                    newEnv <- liftIO $ LSC.nullEnvWithImport+                    -- compile the module code, again per eval-module+                    result <- compileModule newEnv metaEnv name mod lopts $+                        CompileOptions symStartLoadNewEnv False False (Just symEndLoadNewEnv)+                    modWEnv <- eval metaEnv $ List (Atom "module-env-set!" : mod' : [LispEnv newEnv]) +                    -- Above does not update *modules* correctly, so we del/add below+                    _ <- eval metaEnv $ List [Atom "delete-module!", List [Atom "quote", name]]+                    _ <- eval metaEnv $ List [Atom "add-module!", List [Atom "quote", name], modWEnv]++                    return $ +                     [createAstFunc copts newEnvFunc] +++                     [createAstFunc (CompileOptions symEndLoadNewEnv False False Nothing)+                                    [AstValue "  return $ Nil \"\""]] +++                     result+                _ -> return [] --mod++-- |Compile the given module, using metadata loaded into memory.+--  This code is based off of eval-module from the meta language.+compileModule env metaEnv name mod lopts +              copts@(CompileOptions thisFunc _ _ lastFunc) = do+    -- TODO: set mod meta-data to avoid cyclic references+    -- see modules.scm for how this is done by the interpreter+    Atom afterImportsFnc <- _gensym "modAfterImport"+    Atom afterDirFunc <- _gensym "modAfterDir"++    metaData <- LSC.evalLisp metaEnv $ +                  List [Atom "module-meta-data", List [Atom "quote", mod]]++    moduleImports <- cmpSubMod env metaEnv metaData lopts $ +        CompileOptions thisFunc False False (Just afterImportsFnc)+    moduleDirectives <- cmpModExpr env metaEnv name metaData lopts $+        moduleDirsCopts moduleImports afterImportsFnc++    return $ moduleImports ++ +             moduleDirectives ++ +            (moduleStub moduleImports moduleDirectives afterImportsFnc)+ where +  moduleDirsCopts modImps afterImportsFnc = do+-- if moduleImports is [] then use same copts for moduleDir+-- else, use copts (afterImportsFunc, lastFunc)+    case modImps of+        [] -> CompileOptions thisFunc False False (Just afterImportsFnc)+        _ -> CompileOptions afterImportsFnc False False lastFunc+  moduleStub modImps modDir afterImportsFnc = do+-- if moduleDir == [] and moduleimports == [] then add stub (this, last)+-- else if modDir == [] then addstub (afterimports, last)+-- else, no stub required+    case (modImps, modDir) of+        ([], []) -> [createFunctionStub thisFunc lastFunc]+        ([], _) -> [createFunctionStub afterImportsFnc lastFunc]+        (_, []) -> [createFunctionStub afterImportsFnc lastFunc]+        _ -> [] -- Both have code, no stub needed++-- Helper function to create an empty continuation+--+-- TODO: ideally stubs would not be necessary,+--       should refactor out at some point+--createFunctionStub :: String -> HaskAST+createFunctionStub thisFunc nextFunc = do+    createAstFunc (CompileOptions thisFunc True False Nothing)+                  [createAstCont (CompileOptions "" True False nextFunc) +                                 "value" ""]++-- |Compile sub-modules. That is, modules that are imported by+--  another module in the (define-library) definition+cmpSubMod env metaEnv (List ((List (Atom "import-immutable" : modules)) : ls)) +    lopts copts = do+    -- Punt on this for now, although the meta-lang does the same thing+    cmpSubMod env metaEnv +              (List ((List (Atom "import" : modules)) : ls)) +              lopts copts+cmpSubMod env metaEnv (List ((List (Atom "import" : modules)) : ls)) lopts+    copts@(CompileOptions thisFunc _ _ lastFunc) = do+    Atom nextFunc <- _gensym "cmpSubMod"+    code <- importAll env metaEnv modules lopts $ +              CompileOptions thisFunc False False (Just nextFunc)+    rest <- cmpSubMod env metaEnv (List ls) lopts $ +              CompileOptions nextFunc False False lastFunc +    stub <- case rest of +        [] -> return [createFunctionStub nextFunc lastFunc]+        _ -> return []+    return $ code ++ rest ++ stub+cmpSubMod env metaEnv (List (_ : ls)) lopts copts = +    cmpSubMod env metaEnv (List ls) lopts copts+cmpSubMod _ _ _ _ (CompileOptions thisFunc _ _ lastFunc) = +    return [createFunctionStub thisFunc lastFunc]++-- |Compile module directives (expressions) in a module definition+cmpModExpr env metaEnv name (List ((List (Atom "include" : files)) : ls)) +    lopts@(CompileLibraryOptions _ compileLisp)+    copts@(CompileOptions thisFunc _ _ lastFunc) = do+    dir <- LSC.evalLisp metaEnv $ List [Atom "module-name-prefix", +                                        List [Atom "quote", name]]+-- TODO: this pattern is common with the one below in "begin", +--       should consolidate (or at least consider doing so)+    Atom nextFunc <- _gensym "includeNext"+    code <- includeAll env dir files compileInc lopts $ +                       CompileOptions thisFunc False False (Just nextFunc)+    rest <- cmpModExpr env metaEnv name (List ls) lopts $ +                CompileOptions nextFunc False False lastFunc+    stub <- case rest of +        [] -> return [createFunctionStub nextFunc lastFunc]+        _ -> return []+    return $ code ++ rest ++ stub+ where +  compileInc (String dir) (String filename) entry exit = do+    let path = dir ++ filename+    path' <- LSC.findFileOrLib path+    compileLisp env path' entry exit++cmpModExpr env metaEnv name (List ((List (Atom "include-ci" : code)) : ls)) lopts copts = do+    -- NOTE: per r7rs, ci should insert a fold-case directive. But husk does+    -- not support that, so just do a regular include for now+    cmpModExpr env metaEnv name+       (List ((List (Atom "include" : code)) : ls)) lopts copts+cmpModExpr env metaEnv name (List ((List (Atom "body" : code)) : ls)) lopts copts = do+    cmpModExpr env metaEnv name+       (List ((List (Atom "begin" : code)) : ls)) lopts copts++cmpModExpr env metaEnv name+       (List ((List (Atom "begin" : code)) : ls)) +        lopts@(CompileLibraryOptions compileBlock _)+        copts@(CompileOptions thisFunc _ _ lastFunc) = do+    Atom nextFunc <- _gensym "cmpSubModNext"+    code <- compileBlock thisFunc (Just nextFunc) env [] code+    rest <- cmpModExpr env metaEnv name (List ls) lopts $ +                CompileOptions nextFunc False False lastFunc+    stub <- case rest of +        [] -> return [createFunctionStub nextFunc lastFunc]+        _ -> return []+    return $ code ++ rest ++ stub+cmpModExpr env metaEnv name (List (_ : ls)) lopts copts = +    cmpModExpr env metaEnv name (List ls) lopts copts+cmpModExpr _ _ _ _ _ copts@(CompileOptions thisFunc _ _ lastFunc) =+    return [createFunctionStub thisFunc lastFunc]++-- |Include one or more files for compilation+-- TODO: this pattern is used elsewhere (IE, importAll). could be generalized+includeAll env dir [file] include lopts+          copts@(CompileOptions thisFunc _ _ lastFunc) = do+    include dir file thisFunc lastFunc+includeAll env dir (f : fs) include lopts+           copts@(CompileOptions thisFunc _ _ lastFunc) = do+    Atom nextFunc <- _gensym "includeAll"+    c <- include dir f thisFunc (Just nextFunc)+    rest <- includeAll env dir fs include lopts $+                       CompileOptions nextFunc False False lastFunc+    stub <- case rest of +        [] -> return [createFunctionStub nextFunc lastFunc]+        _ -> return []+    return $ c ++ rest ++ stub+includeAll _ _ [] _ _ _ = return []++-- |Like evalLisp, but preserve pointers in the output+eval :: Env -> LispVal -> IOThrowsError LispVal+eval env lisp = do+  LSC.meval env (makeNullContinuation env) lisp+
+ hs-src/Language/Scheme/Compiler/Types.hs view
@@ -0,0 +1,242 @@+{- |+Module      : Language.Scheme.Compiler.Types+Copyright   : Justin Ethier+Licence     : MIT (see LICENSE in the distribution)++Maintainer  : github.com/justinethier+Stability   : experimental+Portability : portable++This module contains data types used by the compiler.+-}++module Language.Scheme.Compiler.Types +    (+    -- * Data types+      CompOpts (CompileOptions)+    , CompLibOpts (..)+    , defaultCompileOptions+    , HaskAST (..)+    -- * Utility functions+    , ast2Str+    , asts2Str+    , createAstFunc +    , createAstCont +    , joinL +    , moduleRuntimeVar+    , showValAST+    -- * Headers appended to output file+    , header+    , headerComment+    , headerModule+    , headerImports+    )+where +import qualified Language.Scheme.Core as LSC (version) +import Language.Scheme.Types+import qualified Language.Scheme.Util (escapeBackslashes)+import qualified Data.Array+import qualified Data.ByteString as BS+import qualified Data.Complex as DC+import qualified Data.List+import qualified Data.Map+import qualified Data.Ratio as DR++-- |A type to store options passed to compile.+--  Eventually all of this might be able to be +--  integrated into a Compile monad.+data CompOpts = CompileOptions {+    coptsThisFunc :: String,        +    -- ^Immediate name to use when creating a compiled function.+    --  Presumably there is other code that is expecting+    --  to call into it.++    coptsThisFuncUseValue :: Bool,+    -- ^Whether to include the 'value' parameter in the current function+    +    coptsThisFuncUseArgs :: Bool,+    -- ^Whether to include the 'args' parameter in the current function+    +    coptsNextFunc :: Maybe String+    -- ^The name to use for the next function after the current+    --  compiler recursion is finished. For example, after compiling+    --  a block of code, the control flow would be expected to go+    --  to this function.+    }++defaultCompileOptions :: String -> CompOpts+defaultCompileOptions thisFunc = CompileOptions thisFunc False False Nothing++-- |Options passed to the compiler library module+data CompLibOpts = CompileLibraryOptions {+    compBlock :: String -> Maybe String -> Env +              -> [HaskAST] -> [LispVal] -> IOThrowsError [HaskAST],+    compLisp :: Env -> String -> String -> Maybe String +              -> IOThrowsError [HaskAST]+    }++-- |Runtime reference to module data structure+moduleRuntimeVar = " modules "++-- |Create code for a function+createAstFunc +  :: CompOpts  -- ^ Compilation options+  -> [HaskAST] -- ^ Body of the function+  -> HaskAST -- ^ Complete function code+createAstFunc (CompileOptions thisFunc useVal useArgs _) funcBody = do+  let val = case useVal of+              True -> "value"+              _ -> "_"+      args = case useArgs of+               True -> "(Just args)"+               _ -> "_"+  AstFunction thisFunc (" env cont " ++ val ++ " " ++ args ++ " ") funcBody++-- |Create code for a continutation+createAstCont +  :: CompOpts -- ^ Compilation options+  -> String -- ^ Value to send to the continuation+  -> String -- ^ Extra leading indentation (or blank string if none)+  -> HaskAST -- ^ Generated code+createAstCont (CompileOptions _ _ _ (Just nextFunc)) var indentation = do+  AstValue $ indentation ++ "  continueEval env (makeCPS env cont " ++ nextFunc ++ ") " ++ var+createAstCont (CompileOptions _ _ _ Nothing) var indentation = do+  AstValue $ indentation ++ "  continueEval env cont " ++ var+++--  FUTURE: is this even necessary? Would just a string be good enough?++-- |A very basic type to store a Haskell AST.+data HaskAST = AstAssignM String HaskAST+  | AstFunction {astfName :: String,+--                 astfType :: String,+                 astfArgs :: String,+                 astfCode :: [HaskAST]+                } + | AstValue String+ | AstContinuation {astcNext :: String,+                    astcArgs :: String+                   }++-- |Generate code based on the given Haskell AST+showValAST :: HaskAST -> String+showValAST (AstAssignM var val) = "  " ++ var ++ " <- " ++ show val+showValAST (AstFunction name args code) = do+  let fheader = "\n" ++ name ++ args ++ " = do "+  let fbody = unwords . map (\x -> "\n" ++ x ) $ map showValAST code+  fheader ++ fbody +showValAST (AstValue v) = v+showValAST (AstContinuation nextFunc args) =+    "  continueEval env (makeCPSWArgs env cont " ++ +       nextFunc ++ " " ++ args ++ ") $ Nil \"\""++instance Show HaskAST where show = showValAST++-- |A utility function to join list members together+joinL +  :: forall a. [[a]] -- ^ Original list-of-lists+  -> [a] -- ^ Separator +  -> [a] -- ^ Joined list+joinL ls sep = concat $ Data.List.intersperse sep ls++-- |Convert abstract syntax tree to a string+ast2Str :: LispVal -> String +ast2Str (String s) = "String " ++ show s+ast2Str (Char c) = "Char " ++ show c+ast2Str (Atom a) = "Atom " ++ show a+ast2Str (Number n) = "Number (" ++ show n ++ ")"+ast2Str (Complex c) = "Complex $ (" ++ (show $ DC.realPart c) ++ ") :+ (" ++ (show $ DC.imagPart c) ++ ")"+ast2Str (Rational r) = "Rational $ (" ++ (show $ DR.numerator r) ++ ") % (" ++ (show $ DR.denominator r) ++ ")"+ast2Str (Float f) = "Float (" ++ show f ++ ")"+ast2Str (Bool True) = "Bool True"+ast2Str (Bool False) = "Bool False"+ast2Str (HashTable ht) = do+ let ls = Data.Map.toList ht +     conv (a, b) = "(" ++ ast2Str a ++ "," ++ ast2Str b ++ ")"+ "HashTable $ Data.Map.fromList $ [" ++ joinL (map conv ls) "," ++ "]"+ast2Str (Vector v) = do+  let ls = Data.Array.elems v+      size = (length ls) - 1+  "Vector (listArray (0, " ++ show size ++ ")" ++ "[" ++ joinL (map ast2Str ls) "," ++ "])"+ast2Str (ByteVector bv) = do+  let ls = BS.unpack bv+  "ByteVector ( BS.pack " ++ "[" ++ joinL (map show ls) "," ++ "])"+ast2Str (List ls) = "List [" ++ joinL (map ast2Str ls) "," ++ "]"+ast2Str (DottedList ls l) = +  "DottedList [" ++ joinL (map ast2Str ls) "," ++ "] $ " ++ ast2Str l++-- |Convert a list of abstract syntax trees to a list of strings+asts2Str :: [LispVal] -> String+asts2Str ls = do+    "[" ++ (joinL (map ast2Str ls) ",") ++ "]"++headerComment, headerModule, headerImports :: [String]+headerComment = [+   "--"+ , "-- This file was automatically generated by the husk scheme compiler (huskc)"+ , "--"+ , "--  http://justinethier.github.io/husk-scheme "+ , "--  (c) 2010 Justin Ethier "+ , "--  Version " ++ LSC.version+ , "--"]++headerModule = ["module Main where "]+headerImports = [+   "Language.Scheme.Core "+ , "Language.Scheme.Numerical "+ , "Language.Scheme.Primitives "+ , "Language.Scheme.Types     -- Scheme data types "+ , "Language.Scheme.Variables -- Scheme variable operations "+ , "Control.Monad.Error "+ , "Data.Array "+ , " qualified Data.ByteString as BS "+ , "Data.Complex "+ , " qualified Data.Map "+ , "Data.Ratio "+ , "Data.Word "+ , "System.IO "]++header :: String -> Bool -> [String]+header filepath useCompiledLibs = do+  let env = if useCompiledLibs+            then "primitiveBindings"+            else "r5rsEnv"+  [ " "+    , "-- |Get variable at runtime "+    , "getRTVar env var = do " +    , "  v <- getVar env var " +    , "  return $ case v of "+    , "    List _ -> Pointer var env "+    , "    DottedList _ _ -> Pointer var env "+    , "    String _ -> Pointer var env "+    , "    Vector _ -> Pointer var env "+    , "    ByteVector _ -> Pointer var env "+    , "    HashTable _ -> Pointer var env "+    , "    _ -> v "+    , " "+    , "applyWrapper env cont (Nil _) (Just (a:as))  = do "+    , "  apply cont a as "+    , " "+    , "applyWrapper env cont value (Just (a:as))  = do "+    , "  apply cont a $ as ++ [value] "+    , " "+    , "getDataFileName' :: FilePath -> IO FilePath "+    , "getDataFileName' name = return $ \"" ++ (Language.Scheme.Util.escapeBackslashes filepath) ++ "\" ++ name "+    , " "+    , "exec55_3 env cont _ _ = do "+    , "  liftIO $ registerExtensions env getDataFileName' "+    , "  continueEval env (makeCPS env cont exec) (Nil \"\")"+    , " "+    , "main :: IO () "+    , "main = do "+    , "  env <- " ++ env ++ " "+    , "  result <- (runIOThrows $ liftM show $ hsInit env (makeNullContinuation env) (Nil \"\") Nothing) "+    , "  case result of "+    , "    Just errMsg -> putStrLn errMsg "+    , "    _ -> return () "+    , " "+    , "hsInit env cont _ _ = do "+    , "  _ <- defineVar env \"" ++ moduleRuntimeVar ++ "\" $ HashTable $ Data.Map.fromList [] "+    , "  run env cont (Nil \"\") []"+    , " "]+
hs-src/Language/Scheme/Core.hs view
@@ -24,11 +24,14 @@     , runIOThrows      , runIOThrowsREPL      -- * Core data+    , nullEnvWithImport     , primitiveBindings     , r5rsEnv+    , r5rsEnv'     -- , r7rsEnv     , version     -- * Utility functions+    , findFileOrLib     , getDataFileFullPath     , registerExtensions     , showBanner@@ -36,6 +39,8 @@     , substr     , updateVector     , updateByteVector+    -- * Internal use only+    , meval     ) where import qualified Paths_husk_scheme as PHS (getDataFileName) #ifdef UseFfi@@ -61,7 +66,7 @@  -- |husk version number version :: String-version = "3.10"+version = "3.11"  -- |A utility function to display the husk console banner showBanner :: IO ()@@ -81,6 +86,26 @@ getDataFileFullPath :: String -> IO String getDataFileFullPath s = PHS.getDataFileName s +-- Future use:+-- getDataFileFullPath' :: [LispVal] -> IOThrowsError LispVal+-- getDataFileFullPath' [String s] = do+--     path <- liftIO $ PHS.getDataFileName s+--     return $ String path+-- getDataFileFullPath' [] = throwError $ NumArgs (Just 1) []+-- getDataFileFullPath' args = throwError $ TypeMismatch "string" $ List args++-- |Attempts to find the file both in the current directory and in the husk+--  libraries. If the file is not found in the current directory but exists+--  as a husk library, return the full path to the file in the library.+--  Otherwise just return the given filename.+findFileOrLib filename = do+    fileAsLib <- liftIO $ getDataFileFullPath $ "lib/" ++ filename+    exists <- fileExists [String filename]+    existsLib <- fileExists [String fileAsLib]+    case (exists, existsLib) of+        (Bool False, Bool True) -> return fileAsLib+        _ -> return filename+ -- |Register optional SRFI extensions registerExtensions :: Env -> (FilePath -> IO FilePath) -> IO () registerExtensions env getDataFileName = do@@ -500,17 +525,21 @@  bound <- liftIO $ isRecBound env "string-set!"  if bound   then prepareApply env cont args -- if is bound to a variable in this scope; call into it-  else meval env (makeCPS env cont cpsStr) i+  else meval env (makeCPS env cont cpsChar) character  where+        cpsChar :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal+        cpsChar e c chr _ = do+            meval e (makeCPSWArgs e c cpsStr $ [chr]) i+         cpsStr :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal-        cpsStr e c idx _ = do+        cpsStr e c idx (Just [chr]) = do             value <- getVar env var             derefValue <- derefPtr value-            meval e (makeCPSWArgs e c cpsSubStr $ [idx]) derefValue+            meval e (makeCPSWArgs e c cpsSubStr $ [idx, chr]) derefValue          cpsSubStr :: Env -> LispVal -> LispVal -> Maybe [LispVal] -> IOThrowsError LispVal-        cpsSubStr e c str (Just [idx]) =-            substr (str, character, idx) >>= updateObject e var >>= continueEval e c+        cpsSubStr e c str (Just [idx, chr]) =+            substr (str, chr, idx) >>= updateObject e var >>= continueEval e c         cpsSubStr _ _ _ _ = throwError $ InternalError "Invalid argument to cpsSubStr"  eval env cont args@(List [Atom "string-set!" , nonvar , _ , _ ]) = do@@ -892,14 +921,34 @@ --  For the purposes of using husk as an extension language, /r5rsEnv/ will --  probably be more useful. primitiveBindings :: IO Env-primitiveBindings = nullEnv >>= (flip extendEnv $ map (domakeFunc IOFunc) ioPrimitives-                                               ++ map (domakeFunc EvalFunc) evalFunctions-                                               ++ map (domakeFunc PrimitiveFunc) primitives)-  where domakeFunc constructor (var, func) = ((varNamespace, var), constructor func)+primitiveBindings = nullEnv >>= +    (flip extendEnv $ map (domakeFunc IOFunc) ioPrimitives+                   ++ map (domakeFunc EvalFunc) evalFunctions+                   ++ map (domakeFunc PrimitiveFunc) primitives)+  where domakeFunc constructor (var, func) = +            ((varNamespace, var), constructor func) +-- |An empty environment with the %import function. This is presently+--  just intended for internal use by the compiler.+nullEnvWithImport :: IO Env+nullEnvWithImport = nullEnv >>= +  (flip extendEnv [+    ((varNamespace, "%import"), EvalFunc evalfuncImport),+    ((varNamespace, "hash-table-ref"), IOFunc $ wrapHashTbl hashTblRef)])+ -- |Load the standard r5rs environment, including libraries r5rsEnv :: IO Env r5rsEnv = do+  env <- r5rsEnv'+  -- Bit of a hack to load (import)+  _ <- evalLisp' env $ List [Atom "%bootstrap-import"]++  return env++-- |Load the standard r5rs environment, including libraries,+--  but do not create the (import) binding+r5rsEnv' :: IO Env+r5rsEnv' = do   env <- primitiveBindings   stdlib <- PHS.getDataFileName "lib/stdlib.scm"   srfi55 <- PHS.getDataFileName "lib/srfi/srfi-55.scm" -- (require-extension)@@ -918,8 +967,6 @@   _ <- evalString metaEnv $ "(load \"" ++ (escapeBackslashes metalib) ++ "\")"   -- Load meta-env so we can find it later   _ <- evalLisp' env $ List [Atom "define", Atom "*meta-env*", LispEnv metaEnv]-  -- Bit of a hack to load (import)-  _ <- evalLisp' env $ List [Atom "%bootstrap-import"]   -- Load (r5rs base)   _ <- evalString metaEnv          "(add-module! '(scheme r5rs) (make-module #f (interaction-environment) '()))"@@ -1056,13 +1103,15 @@             LispEnv e -> return toEnv             Bool False -> do                 -- A hack to load imports into the main env, which-                -- in modules.scm is the grandparent env+                -- in modules.scm is the parent env                 case parentEnv env of-                    Just (Environment (Just gp) _ _) -> -                        return $ LispEnv gp-                    Just (Environment Nothing _ _ ) -> throwError $ InternalError "import into empty parent env"+                    Just env -> return $ LispEnv env                     Nothing -> throwError $ InternalError "import into empty env"     case imports of+        List [Bool False] -> do -- Export everything+            exportAll toEnv'+        Bool False -> do -- Export everything+            exportAll toEnv'         p@(Pointer _ _) -> do             -- TODO: need to do this in a safer way             List i <- derefPtr p -- Dangerous, but list is only expected obj@@ -1071,16 +1120,17 @@         List i -> do             result <- moduleImport toEnv' fromEnv i             continueEval env cont result-        Bool False -> do -- Export everything-            newEnv <- liftIO $ importEnv toEnv' fromEnv-            continueEval-                env -               (Continuation env a b c d) -               (LispEnv newEnv)+ where +   exportAll toEnv' = do+     newEnv <- liftIO $ importEnv toEnv' fromEnv+     continueEval+         env +        (Continuation env a b c d) +        (LispEnv newEnv)  -- This is just for debugging purposes:-evalfuncImport (cont@(Continuation env _ _ _ _ ) : cs) = do-    continueEval env cont $ Nil ""+evalfuncImport args@(cont@(Continuation env _ _ _ _ ) : cs) = do+    throwError $ TypeMismatch "import fields" $ List cs  -- |Load import into the main environment bootstrapImport [cont@(Continuation env _ _ _ _)] = do@@ -1098,17 +1148,8 @@     evalfuncLoad [Continuation env a b c d, String filename]  evalfuncLoad [cont@(Continuation env _ _ _ _), String filename] = do-{---- It would be nice to use CPS style below.------ This code mostly works, but causes looping problems in t-cont. need to test to see if--- those are an artifact of this change or a code problem in that test suite:-  code <- load filename-  if not (null code)-     then continueEval env (Continuation env (Just $ SchemeBody code) (Just cont) Nothing Nothing) $ Nil "" -     else return $ Nil "" -- Empty, unspecified value--}-    results <- load filename >>= mapM (evaluate env (makeNullContinuation env))+    filename' <- findFileOrLib filename+    results <- load filename' >>= mapM (evaluate env (makeNullContinuation env))     if not (null results)        then do result <- return . last $ results                continueEval env cont result@@ -1283,6 +1324,9 @@                 -- From SRFI 96                 ("file-exists?", fileExists),                 ("delete-file", deleteFile),++                -- husk internal functions+                --("husk-path", getDataFileFullPath'),                  -- Other I/O functions                 ("print-env", printEnv'),
hs-src/Language/Scheme/Libraries.hs view
@@ -42,6 +42,7 @@       file == "scheme/r5rs/read.sld" ||       file == "scheme/r5rs/write.sld" ||       file == "scheme/base.sld" ||+      file == "husk/pretty-print.sld" || -- TODO: scheme case-lambda (r7rs) -- TODO: scheme process-context (r7rs) -- TODO: scheme repl (r7rs)@@ -69,9 +70,8 @@   moduleImport to from is moduleImport to from [] = do   return $ LispEnv to--- DEBUG:--- moduleImport to from unknown = do---   (trace ("MODULE IMPORT DEBUG: " ++ show unknown) return) $ Nil ""+moduleImport _ _ err = do+  throwError $ Default $ "Unexpected argument to moduleImport: " ++ show err  -- |Copy a binding from one env to another divertBinding
hs-src/Language/Scheme/Primitives.hs view
@@ -550,7 +550,9 @@ stringLength badArgList = throwError $ NumArgs (Just 1) badArgList  stringRef :: [LispVal] -> IOThrowsError LispVal-stringRef [p@(Pointer _ _)] = derefPtr p >>= box >>= stringRef+stringRef [p@(Pointer _ _), k@(Number _)] = do+    s <- derefPtr p +    stringRef [s, k] stringRef [(String s), (Number k)] = return $ Char $ s !! fromInteger k stringRef [badType] = throwError $ TypeMismatch "string number" badType stringRef badArgList = throwError $ NumArgs (Just 2) badArgList
hs-src/Language/Scheme/Types.hs view
@@ -73,6 +73,7 @@         , LispEnv         , EOF         , Nil)+    , nullLisp     , toOpaque     , fromOpaque     , DeferredCode (..)@@ -260,6 +261,10 @@    -- ^ End of file indicator  | Nil String  -- ^Internal use only; do not use this type directly.++-- | Scheme "null" value+nullLisp :: LispVal+nullLisp = List []  -- |Convert a Haskell value to an opaque Lisp value. toOpaque :: Typeable a => a -> LispVal
hs-src/Language/Scheme/Variables.hs view
@@ -18,6 +18,7 @@     (     -- * Environments       printEnv+    , recPrintEnv     , exportsFromEnv      , copyEnv     , extendEnv@@ -107,6 +108,16 @@   showVar (name, val) = do     v <- liftIO $ readIORef val     return $ "[" ++ name ++ "]" ++ ": " ++ show v++recPrintEnv :: Env -> IO String+recPrintEnv env = do+  envStr <- liftIO $ printEnv env++  case parentEnv env of+    Just par -> do+        parEnvStr <- liftIO $ recPrintEnv par+        return $ envStr ++ "\n" ++ parEnvStr+    Nothing -> return envStr  -- |Return a list of symbols exported from an environment exportsFromEnv :: Env 
husk-scheme.cabal view
@@ -1,5 +1,5 @@ Name:                husk-scheme-Version:             3.10+Version:             3.11 Synopsis:            R5RS Scheme interpreter, compiler, and library. Description:            <<https://github.com/justinethier/husk-scheme/raw/master/docs/husk-scheme.png>>@@ -42,7 +42,7 @@                      ChangeLog.markdown                      LICENSE                      AUTHORS-Data-Files:          lib/*.scm lib/scheme/*.sld lib/scheme/r5rs/*.sld lib/srfi/*.scm+Data-Files:          lib/*.scm lib/husk/*.sld lib/husk/*.scm lib/scheme/*.sld lib/scheme/r5rs/*.sld lib/srfi/*.scm  Source-Repository head     Type:            git@@ -68,6 +68,8 @@                    Language.Scheme.Types                    Language.Scheme.Variables                    Language.Scheme.Compiler+                   Language.Scheme.Compiler.Libraries+                   Language.Scheme.Compiler.Types                    Language.Scheme.Plugins.CPUTime                    Language.Scheme.Macro                    Language.Scheme.Macro.ExplicitRenaming
+ lib/husk/pp-sexp.scm view
@@ -0,0 +1,310 @@+;+; Downloaded from:+; http://www.mathematik.uni-muenchen.de/~logik/download/minlog/src/pp-sexp.scm++; JAE - required for below+(define pretty-print #f)+(begin+(define pp-width 80)+; End JAE changes++;; We define a pretty printer for Scheme S-expressions (sexp). While+;; Petite Scheme supports that by its own, mzscheme does not. If you+;; get a sexp (like from proof-to-expr) prefix it with a call to spp and+;; the output is nicely formated to fit into pp-width many columns:+;;+;;  (spp (proof-to-expr (current-proof)))+;;+;; If you want the sexp printed as a comment, use the+;; sexp-pretty-print->string function:+;;+;;  (display-comment (sexp-pretty-print->string+;;                     (proof-to-expr (current-proof))))+;;++;;"genwrite.scm" generic write used by pretty-print and truncated-print.+;; Copyright (c) 1991, Marc Feeley+;; Author: Marc Feeley (feeley@iro.umontreal.ca)+;; Distribution restrictions: none+;;+;; Modified for Minlog by Stefan Schimanski <schimans@math.lmu.de>+;; Taken from slib 2d6, genwrite.scm and pp.scm++(define genwrite:newline-str (make-string 1 #\newline))++(define (generic-write obj display? width output)++  (define (read-macro? l)+    (define (length1? l) (and (pair? l) (null? (cdr l))))+    (let ((head (car l)) (tail (cdr l)))+      (case head+        ((quote quasiquote unquote unquote-splicing) (length1? tail))+        (else                                        #f))))++  (define (read-macro-body l)+    (cadr l))++  (define (read-macro-prefix l)+    (let ((head (car l)) (tail (cdr l)))+      (case head+        ((quote)            "'")+        ((quasiquote)       "`")+        ((unquote)          ",")+        ((unquote-splicing) ",@"))))++  (define (out str col)+    (and col (output str) (+ col (string-length str))))++  (define (wr obj col)++    (define (wr-expr expr col)+      (if (read-macro? expr)+        (wr (read-macro-body expr) (out (read-macro-prefix expr) col))+        (wr-lst expr col)))++    (define (wr-lst l col)+      (if (pair? l)+	  (let loop ((l (cdr l))+		     (col (and col (wr (car l) (out "(" col)))))+	    (cond ((not col) col)+		  ((pair? l)+		   (loop (cdr l) (wr (car l) (out " " col))))+		  ((null? l) (out ")" col))+		  (else      (out ")" (wr l (out " . " col))))))+	  (out "()" col)))++    (cond ((pair? obj)        (wr-expr obj col))+          ((null? obj)        (wr-lst obj col))+          ((vector? obj)      (wr-lst (vector->list obj) (out "#" col)))+          ((boolean? obj)     (out (if obj "#t" "#f") col))+          ((number? obj)      (out (number->string obj) col))+          ((symbol? obj)      (out (symbol->string obj) col))+          ((procedure? obj)   (out "#[procedure]" col))+          ((string? obj)      (if display?+                                (out obj col)+                                (let loop ((i 0) (j 0) (col (out "\"" col)))+                                  (if (and col (< j (string-length obj)))+                                    (let ((c (string-ref obj j)))+                                      (if (or (char=? c #\\)+                                              (char=? c #\"))+                                        (loop j+                                              (+ j 1)+                                              (out "\\"+                                                   (out (substring obj i j)+                                                        col)))+                                        (loop i (+ j 1) col)))+                                    (out "\""+                                         (out (substring obj i j) col))))))+          ((char? obj)        (if display?+                                (out (make-string 1 obj) col)+                                (out (case obj+                                       ((#\space)   "space")+                                       ((#\newline) "newline")+                                       (else        (make-string 1 obj)))+                                     (out "#\\" col))))+          ((input-port? obj)  (out "#[input-port]" col))+          ((output-port? obj) (out "#[output-port]" col))+          ((eof-object? obj)  (out "#[eof-object]" col))+          (else               (out "#[unknown]" col))))++  (define (pp obj col)++    (define (spaces n col)+      (if (> n 0)+        (if (> n 7)+          (spaces (- n 8) (out "        " col))+          (out (substring "        " 0 n) col))+        col))++    (define (indent to col)+      (and col+           (if (< to col)+             (and (out genwrite:newline-str col) (spaces to 0))+             (spaces (- to col) col))))++    (define (pr obj col extra pp-pair)+      (if (or (pair? obj) (vector? obj)) ; may have to split on multiple lines+        (let ((result '())+              (left (min (+ (- (- width col) extra) 1) max-expr-width)))+          (generic-write obj display? #f+            (lambda (str)+              (set! result (cons str result))+              (set! left (- left (string-length str)))+              (> left 0)))+          (if (> left 0) ; all can be printed on one line+            (out (reverse-string-append result) col)+            (if (pair? obj)+              (pp-pair obj col extra)+              (pp-list (vector->list obj) (out "#" col) extra pp-expr))))+        (wr obj col)))++    (define (pp-expr expr col extra)+      (if (read-macro? expr)+        (pr (read-macro-body expr)+            (out (read-macro-prefix expr) col)+            extra+            pp-expr)+        (let ((head (car expr)))+          (if (symbol? head)+            (let ((proc (style head)))+              (if proc+                (proc expr col extra)+                (if (> (string-length (symbol->string head))+                       max-call-head-width)+                  (pp-general expr col extra #f #f #f pp-expr)+                  (pp-call expr col extra pp-expr))))+            (pp-list expr col extra pp-expr)))))++    ; (head item1+    ;       item2+    ;       item3)+    (define (pp-call expr col extra pp-item)+      (let ((col* (wr (car expr) (out "(" col))))+        (and col+             (pp-down (cdr expr) col* (+ col* 1) extra pp-item))))++    ; (item1+    ;  item2+    ;  item3)+    (define (pp-list l col extra pp-item)+      (let ((col (out "(" col)))+        (pp-down l col col extra pp-item)))++    (define (pp-down l col1 col2 extra pp-item)+      (let loop ((l l) (col col1))+        (and col+             (cond ((pair? l)+                    (let ((rest (cdr l)))+                      (let ((extra (if (null? rest) (+ extra 1) 0)))+                        (loop rest+                              (pr (car l) (indent col2 col) extra pp-item)))))+                   ((null? l)+                    (out ")" col))+                   (else+                    (out ")"+                         (pr l+                             (indent col2 (out "." (indent col2 col)))+                             (+ extra 1)+                             pp-item)))))))++    (define (pp-general expr col extra named? pp-1 pp-2 pp-3)++      (define (tail1 rest col1 col2 col3)+        (if (and pp-1 (pair? rest))+          (let* ((val1 (car rest))+                 (rest (cdr rest))+                 (extra (if (null? rest) (+ extra 1) 0)))+            (tail2 rest col1 (pr val1 (indent col3 col2) extra pp-1) col3))+          (tail2 rest col1 col2 col3)))++      (define (tail2 rest col1 col2 col3)+        (if (and pp-2 (pair? rest))+          (let* ((val1 (car rest))+                 (rest (cdr rest))+                 (extra (if (null? rest) (+ extra 1) 0)))+            (tail3 rest col1 (pr val1 (indent col3 col2) extra pp-2)))+          (tail3 rest col1 col2)))++      (define (tail3 rest col1 col2)+        (pp-down rest col2 col1 extra pp-3))++      (let* ((head (car expr))+             (rest (cdr expr))+             (col* (wr head (out "(" col))))+        (if (and named? (pair? rest))+          (let* ((name (car rest))+                 (rest (cdr rest))+                 (col** (wr name (out " " col*))))+            (tail1 rest (+ col indent-general) col** (+ col** 1)))+          (tail1 rest (+ col indent-general) col* (+ col* 1)))))++    (define (pp-expr-list l col extra)+      (pp-list l col extra pp-expr))++    (define (pp-LAMBDA expr col extra)+      (pp-general expr col extra #f pp-expr-list #f pp-expr))++    (define (pp-IF expr col extra)+      (pp-general expr col extra #f pp-expr #f pp-expr))++    (define (pp-COND expr col extra)+      (pp-call expr col extra pp-expr-list))++    (define (pp-CASE expr col extra)+      (pp-general expr col extra #f pp-expr #f pp-expr-list))++    (define (pp-AND expr col extra)+      (pp-call expr col extra pp-expr))++    (define (pp-LET expr col extra)+      (let* ((rest (cdr expr))+             (named? (and (pair? rest) (symbol? (car rest)))))+        (pp-general expr col extra named? pp-expr-list #f pp-expr)))++    (define (pp-BEGIN expr col extra)+      (pp-general expr col extra #f #f #f pp-expr))++    (define (pp-DO expr col extra)+      (pp-general expr col extra #f pp-expr-list pp-expr-list pp-expr))++    ; define formatting style (change these to suit your style)++    (define indent-general 2)++    (define max-call-head-width 5)++    (define max-expr-width 50)++    (define (style head)+      (case head+        ((lambda let* letrec define) pp-LAMBDA)+        ((if set!)                   pp-IF)+        ((cond)                      pp-COND)+        ((case)                      pp-CASE)+        ((and or)                    pp-AND)+        ((let)                       pp-LET)+        ((begin)                     pp-BEGIN)+        ((do)                        pp-DO)+        (else                        #f)))++    (pr obj col 0 pp-expr))++  (if width+    (out genwrite:newline-str (pp obj 0))+    (wr obj 0)))++; (reverse-string-append l) = (apply string-append (reverse l))++(define (reverse-string-append l)++  (define (rev-string-append l i)+    (if (pair? l)+      (let* ((str (car l))+             (len (string-length str))+             (result (rev-string-append (cdr l) (+ i len))))+        (let loop ((j 0) (k (- (- (string-length result) i) len)))+          (if (< j len)+            (begin+              (string-set! result k (string-ref str j))+              (loop (+ j 1) (+ k 1)))+            result)))+      (make-string i)))++  (rev-string-append l 0))++(define (sexp-pretty-print obj . opt)+  (let ((port (if (pair? opt) (car opt) (current-output-port))))+    (generic-write obj #f pp-width+		   (lambda (s) (display s port) #t))+    (display "")))++(define (sexp-pretty-print->string obj . width)+  (define result '())+  (generic-write obj #f (if (null? width) pp-width (car width))+		 (lambda (str) (set! result (cons str result)) #t))+  (reverse-string-append result))++(define spp sexp-pretty-print)+(set! pretty-print spp)+)+
+ lib/husk/pretty-print.sld view
@@ -0,0 +1,4 @@+(define-library (husk pretty-print)+    (export pretty-print)+    (import (scheme r5rs))+    (include "pp-sexp.scm"))
lib/modules.scm view
@@ -8,7 +8,7 @@ ;;; used to implement modules (r7rs libraries) in husk ;;; -;; meta.scm -- meta langauge for describing modules+;; meta.scm -- meta language for describing modules ;; Copyright (c) 2009-2012 Alex Shinn.  All rights reserved. ;; BSD-style license: http://synthcode.com/license.txt @@ -157,10 +157,11 @@            (cond             ((find-module-file f)              => (lambda (path)-                  (cond (fold?-                         (let ((in (open-input-file path)))-                           (set-port-fold-case! in #t)-                           (load in env)))+                        ;; JAE+                  (cond ;(fold?+                        ; (let ((in (open-input-file path)))+                        ;   (set-port-fold-case! in #t)+                        ;   (load in env)))                         (else                          (load path env)))))             (else (error "couldn't find include" f)))))@@ -187,8 +188,9 @@           (load-modules (cdr x) "" #f))          ((include-ci)           (load-modules (cdr x) "" #t))-         ((include-shared)-          (load-modules (cdr x) *shared-object-extension* #f))+         ;; JAE+         ;((include-shared)+         ; (load-modules (cdr x) *shared-object-extension* #f))          ((body begin)           (for-each              (lambda (expr) 
lib/scheme/r5rs/base.sld view
@@ -78,8 +78,8 @@     for-each     gcd     import-    include-    include-ci+    ;include+    ;include-ci     inexact->exact ; r5rs definition     input-port?     integer->char
lib/stdlib.scm view
@@ -102,6 +102,17 @@     ((begin exp ...)       ((lambda () exp ...))))) +;+;+; NOTE: The below cond/case forms do NOT use begin to prevent+;       conflicts between the stdlib begin and the begin form+;       from the module metalanguage.+;+; TODO: this may indicate a problem with syntax-rules and+;       referential transparency.+;+;+ ; cond ; Form from R5RS: (define-syntax cond@@ -119,8 +130,7 @@ ; updated to take this into acccount, so the pitfall ; still fails ;-     ;(begin result1 result2 ...)) ;; TODO: should use begin-     ((lambda () result1 result2 ...))) ;; TODO: should use begin+     ((lambda () result1 result2 ...))) ;; Intentionally not using begin, see above     ((cond (test => result))      (let ((temp test))        (if temp (result temp))))@@ -136,13 +146,11 @@            temp            (cond clause1 clause2 ...))))     ((cond (test result1 result2 ...))-     ;(if test (begin result1 result2 ...))) ;; TODO: should use begin-     (if test ((lambda () result1 result2 ...)))) ;; TODO: should use begin+     (if test ((lambda () result1 result2 ...)))) ;; Intentionally not using begin, see above     ((cond (test result1 result2 ...)            clause1 clause2 ...)      (if test-         ;(begin result1 result2 ...) ;; TODO: should use begin-         ((lambda () result1 result2 ...)) ;; TODO: should use begin+         ((lambda () result1 result2 ...)) ;; Intentionally not using begin, see above          (cond clause1 clause2 ...))))) ; Case ; Form from R5RS:@@ -154,19 +162,16 @@        (case atom-key clauses ...)))     ((case key        (else result1 result2 ...))-     ;(if #t (begin result1 result2 ...))) ;; TODO: should use begin-     (if #t ((lambda () result1 result2 ...)))) ;; TODO: should use begin+     (if #t ((lambda () result1 result2 ...)))) ;; Intentionally not using begin, see above     ((case key        ((atoms ...) result1 result2 ...))      (if (memv key '(atoms ...))-         ;(begin result1 result2 ...))) ;; TODO: should use begin-         ((lambda () result1 result2 ...)))) ;; TODO: should use begin+         ((lambda () result1 result2 ...)))) ;; Intentionally not using begin, see above     ((case key        ((atoms ...) result1 result2 ...)        clause clauses ...)      (if (memv key '(atoms ...))-         ;(begin result1 result2 ...) ;; TODO: should use begin-         ((lambda () result1 result2 ...)) ;; TODO: should use begin+         ((lambda () result1 result2 ...)) ;; Intentionally not using begin, see above          (case key clause clauses ...)))))  (define (my-mem-helper obj lst cmp-proc)