module Language.Scheme.Macro
(
expand
, macroEval
, loadMacros
, getDivertedVars
) where
import Language.Scheme.Types
import Language.Scheme.Variables
import Language.Scheme.Macro.ExplicitRenaming
import qualified Language.Scheme.Macro.Matches as Matches
import Language.Scheme.Primitives (_gensym)
import Control.Monad.Error
import Data.Array
getDivertedVars :: Env -> IOThrowsError [LispVal]
getDivertedVars env = do
List tmp <- getNamespacedVar env ' ' "diverted"
return tmp
clearDivertedVars :: Env -> IOThrowsError LispVal
clearDivertedVars env = defineNamespacedVar env ' ' "diverted" $ List []
macroEval :: Env
-> LispVal
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> IOThrowsError LispVal
macroEval env lisp@(List (Atom x : _)) apply = do
_ <- clearDivertedVars env
_macroEval env lisp apply
macroEval env lisp apply = _macroEval env lisp apply
_macroEval env lisp@(List (Atom x : _)) apply = do
var <- getNamespacedVar' env macroNamespace x
case var of
Just (SyntaxExplicitRenaming transformer@(Func _ _ _ _)) -> do
renameEnv <- liftIO $ nullEnv
expanded <- explicitRenamingTransform env renameEnv
lisp transformer apply
_macroEval env expanded apply
Just (Syntax (Just defEnv) _ definedInMacro ellipsis identifiers rules) -> do
renameEnv <- liftIO $ nullEnv
cleanupEnv <- liftIO $ nullEnv
expanded <- macroTransform defEnv env env renameEnv cleanupEnv
definedInMacro
(List identifiers) rules lisp apply
ellipsis
_macroEval env expanded apply
Nothing -> return lisp
_macroEval _ lisp@(_) _ = return lisp
macroTransform ::
Env
-> Env
-> Env
-> Env
-> Env
-> Bool
-> LispVal
-> [LispVal]
-> LispVal
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> String
-> IOThrowsError LispVal
macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers (rule@(List _) : rs) input apply esym = do
localEnv <- liftIO $ nullEnv
result <- matchRule defEnv env divertEnv dim identifiers localEnv renameEnv cleanupEnv rule input esym
case (result) of
Nil _ -> macroTransform defEnv env divertEnv renameEnv cleanupEnv dim identifiers rs input apply esym
_ -> do
walkExpanded defEnv env divertEnv renameEnv cleanupEnv dim True False (List []) (result) apply
macroTransform _ _ _ _ _ _ _ _ input _ _ = throwError $ BadSpecialForm "Input does not match a macro pattern" input
macroElementMatchesMany :: LispVal -> String -> Bool
macroElementMatchesMany args@(List (_ : ps)) ellipsisSym = do
if not (null ps)
then (head ps) == (Atom ellipsisSym)
else False
macroElementMatchesMany _ _ = False
matchRule :: Env -> Env -> Env -> Bool -> LispVal -> Env -> Env -> Env -> LispVal -> LispVal -> String -> IOThrowsError LispVal
matchRule defEnv outerEnv divertEnv dim identifiers localEnv renameEnv cleanupEnv (List [pattern, template]) (List inputVar) esym = do
let is = tail inputVar
let p = case pattern of
DottedList ds d -> case ds of
(Atom l : ls) -> (List [Atom l, DottedList ls d], True)
_ -> (pattern, False)
_ -> (pattern, False)
case p of
((List (Atom _ : ps)), flag) -> do
match <- checkPattern ps is flag
case match of
Bool False -> return $ Nil ""
_ -> do
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym 0 [] (List []) template
_ -> throwError $ BadSpecialForm "Malformed rule in syntax-rules" $ String $ show p
where
checkPattern ps@(DottedList ds d : _) is True = do
case is of
(DottedList _ _ : _) -> do
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers
(List $ ds ++ [d, Atom esym])
(List is)
0 []
(flagDottedLists [] (False, False) 0)
esym
(List _ : _) -> do
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers
(List $ ds ++ [d, Atom esym])
(List is)
0 []
(flagDottedLists [] (True, False) 0)
esym
_ -> loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List ps) (List is) 0 [] [] esym
checkPattern ps is _ = loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List ps) (List is) 0 [] [] esym
matchRule _ _ _ _ _ _ _ _ rule input _ = do
throwError $ BadSpecialForm "Malformed rule in syntax-rules" $ List [Atom "rule: ", rule, Atom "input: ", input]
loadLocal :: Env -> Env -> Env -> Env -> Env -> LispVal -> LispVal -> LispVal -> Int -> [Int] -> [(Bool, Bool)] -> String -> IOThrowsError LispVal
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers pattern input ellipsisLevel ellipsisIndex listFlags esym = do
case (pattern, input) of
((DottedList ps p), (DottedList isRaw iRaw)) -> do
let isSplit = splitAt (length ps) isRaw
let is = fst isSplit
let i = (snd isSplit) ++ [iRaw]
result <- loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List ps) (List is) ellipsisLevel ellipsisIndex listFlags esym
case result of
Bool True ->
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers
(List $ [p, Atom esym])
(List i)
ellipsisLevel
ellipsisIndex
(flagDottedLists listFlags (True, True) $ length ellipsisIndex)
esym
_ -> return $ Bool False
(List (p : ps), List (i : is)) -> do
let nextHasEllipsis = macroElementMatchesMany pattern esym
let level = if nextHasEllipsis then ellipsisLevel + 1
else ellipsisLevel
let idx = if nextHasEllipsis
then if (length ellipsisIndex == level)
then do
let l = splitAt (level 1) ellipsisIndex
(fst l) ++ [(head (snd l)) + 1]
else ellipsisIndex ++ [0]
else ellipsisIndex
status <- checkLocal defEnv outerEnv divertEnv (localEnv) renameEnv identifiers level idx p i listFlags esym
case (status) of
Bool False -> if nextHasEllipsis
then do
case ps of
[Atom esym] -> return $ Bool True
_ -> loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List $ tail ps) (List (i : is)) ellipsisLevel ellipsisIndex listFlags esym
else return $ Bool False
_ -> if nextHasEllipsis
then
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers pattern (List is)
ellipsisLevel
idx
listFlags
esym
else loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List ps) (List is) ellipsisLevel ellipsisIndex listFlags esym
(List [], List []) -> return $ Bool True
(List (_ : _), List []) -> do
if (macroElementMatchesMany pattern esym)
then do
let flags = getListFlags (ellipsisIndex ++ [0]) listFlags
flagUnmatchedVars defEnv outerEnv localEnv identifiers pattern (fst flags) esym
else return $ Bool False
(List [], _) -> return $ Bool False
(_, _) -> checkLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers ellipsisLevel ellipsisIndex pattern input listFlags esym
flagUnmatchedVars :: Env -> Env -> Env -> LispVal -> LispVal -> Bool -> String -> IOThrowsError LispVal
flagUnmatchedVars defEnv outerEnv localEnv identifiers (DottedList ps p) partOfImproperPattern esym = do
flagUnmatchedVars defEnv outerEnv localEnv identifiers (List $ ps ++ [p]) partOfImproperPattern esym
flagUnmatchedVars defEnv outerEnv localEnv identifiers (Vector p) partOfImproperPattern esym = do
flagUnmatchedVars defEnv outerEnv localEnv identifiers (List $ elems p) partOfImproperPattern esym
flagUnmatchedVars _ _ _ _ (List []) _ _ = return $ Bool True
flagUnmatchedVars defEnv outerEnv localEnv identifiers (List (p : ps)) partOfImproperPattern esym = do
_ <- flagUnmatchedVars defEnv outerEnv localEnv identifiers p partOfImproperPattern esym
flagUnmatchedVars defEnv outerEnv localEnv identifiers (List ps) partOfImproperPattern esym
flagUnmatchedVars defEnv outerEnv localEnv identifiers (Atom p) partOfImproperPattern esym =
if p == esym
then return $ Bool True
else flagUnmatchedAtom defEnv outerEnv localEnv identifiers p partOfImproperPattern
flagUnmatchedVars _ _ _ _ _ _ _ = return $ Bool True
flagUnmatchedAtom :: Env -> Env -> Env -> LispVal -> String -> Bool -> IOThrowsError LispVal
flagUnmatchedAtom defEnv outerEnv localEnv identifiers p improperListFlag = do
isDefined <- liftIO $ isBound localEnv p
isIdent <- findAtom (Atom p) identifiers
if isDefined
then continueFlagging
else case isIdent of
Bool True -> do
matches <- identifierMatches defEnv outerEnv p
if not matches
then return $ Bool True
else do _ <- flagUnmatchedVar localEnv p improperListFlag
continueFlagging
_ -> do _ <- flagUnmatchedVar localEnv p improperListFlag
continueFlagging
where continueFlagging = return $ Bool True
flagUnmatchedVar :: Env -> String -> Bool -> IOThrowsError LispVal
flagUnmatchedVar localEnv var improperListFlag = do
_ <- defineVar localEnv var $ Nil ""
defineNamespacedVar localEnv
'_'
var $ Bool $ improperListFlag
flagDottedLists :: [(Bool, Bool)] -> (Bool, Bool) -> Int -> [(Bool, Bool)]
flagDottedLists listFlags status lengthOfEllipsisIndex
| length listFlags == lengthOfEllipsisIndex = listFlags ++ [status]
| otherwise = listFlags ++ (replicate ((lengthOfEllipsisIndex) (length listFlags)) (False, False)) ++ [status]
getListFlags :: [Int] -> [(Bool, Bool)] -> (Bool, Bool)
getListFlags elIndices flags
| length elIndices > 0 && length flags >= length elIndices = flags !! ((length elIndices) 1)
| otherwise = (False, False)
checkLocal :: Env
-> Env
-> Env
-> Env
-> Env
-> LispVal
-> Int
-> [Int]
-> LispVal
-> LispVal
-> [(Bool, Bool)]
-> String
-> IOThrowsError LispVal
checkLocal _ _ _ _ _ _ _ _ (Bool pattern) (Bool input) _ _ = return $ Bool $ pattern == input
checkLocal _ _ _ _ _ _ _ _ (Number pattern) (Number input) _ _ = return $ Bool $ pattern == input
checkLocal _ _ _ _ _ _ _ _ (Float pattern) (Float input) _ _ = return $ Bool $ pattern == input
checkLocal _ _ _ _ _ _ _ _ (String pattern) (String input) _ _ = return $ Bool $ pattern == input
checkLocal _ _ _ _ _ _ _ _ (Char pattern) (Char input) _ _ = return $ Bool $ pattern == input
checkLocal defEnv outerEnv _ localEnv renameEnv identifiers ellipsisLevel ellipsisIndex (Atom pattern) input listFlags esym = do
isRenamed <- liftIO $ isRecBound renameEnv (pattern)
doesIdentMatch <- identifierMatches defEnv outerEnv pattern
if (ellipsisLevel) > 0
then do isDefined <- liftIO $ isBound localEnv pattern
isIdent <- findAtom (Atom pattern) identifiers
case isIdent of
Bool True -> do
case input of
Atom inpt -> do
if (pattern == inpt)
then if (doesIdentMatch) && (not isRenamed)
then do
addPatternVar isDefined ellipsisLevel ellipsisIndex pattern $ Atom pattern
else return $ Bool False
else return $ Bool False
_ -> return $ Bool False
_ -> addPatternVar isDefined ellipsisLevel ellipsisIndex pattern input
else do
isIdent <- findAtom (Atom pattern) identifiers
case (isIdent) of
Bool True -> do
case input of
Atom inpt -> do
if (pattern == inpt && (doesIdentMatch)) && (not isRenamed)
then do _ <- defineVar localEnv pattern input
return $ Bool True
else return $ (Bool False)
_ -> return $ (Bool False)
_ -> do _ <- defineVar localEnv pattern input
return $ Bool True
where
addPatternVar isDefined ellipLevel ellipIndex pat val
| isDefined = do v <- getVar localEnv pat
case (v) of
Nil _ -> do
_ <- initializePatternVar ellipLevel ellipIndex pat val
return $ Bool False
_ -> do _ <- setVar localEnv pat (Matches.setData v ellipIndex val)
return $ Bool True
| otherwise = do
_ <- initializePatternVar ellipLevel ellipIndex pat val
return $ Bool True
initializePatternVar _ ellipIndex pat val = do
let flags = getListFlags ellipIndex listFlags
_ <- defineVar localEnv pat (Matches.setData (List []) ellipIndex val)
_ <- defineNamespacedVar localEnv 'p' pat $ Bool $ fst flags
defineNamespacedVar localEnv 'i' pat $ Bool $ snd flags
checkLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers ellipsisLevel ellipsisIndex (Vector p) (Vector i) flags esym =
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers (List $ elems p) (List $ elems i) ellipsisLevel ellipsisIndex flags esym
checkLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers ellipsisLevel ellipsisIndex pattern@(DottedList _ _) input@(DottedList _ _) flags esym =
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers pattern input ellipsisLevel ellipsisIndex flags esym
checkLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers ellipsisLevel ellipsisIndex (DottedList ps p) input@(List (_ : _)) flags esym = do
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers
(List $ ps ++ [p, Atom esym])
input
ellipsisLevel
ellipsisIndex
(flagDottedLists flags (True, False) $ length ellipsisIndex)
esym
checkLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers ellipsisLevel ellipsisIndex pattern@(List _) input@(List _) flags esym =
loadLocal defEnv outerEnv divertEnv localEnv renameEnv identifiers pattern input ellipsisLevel ellipsisIndex flags esym
checkLocal _ _ _ _ _ _ _ _ _ _ _ _ = return $ Bool False
identifierMatches :: Env -> Env -> String -> IOThrowsError Bool
identifierMatches defEnv useEnv ident = do
atDef <- liftIO $ isRecBound defEnv ident
atUse <- liftIO $ isRecBound useEnv ident
matchIdent atDef atUse
where
matchIdent False False = return True
matchIdent True True = do
d <- getVar defEnv ident
u <- getVar useEnv ident
return $ eqVal d u
matchIdent _ _ = return False
expand ::
Env
-> Bool
-> LispVal
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> IOThrowsError LispVal
expand env dim code apply = do
renameEnv <- liftIO $ nullEnv
cleanupEnv <- liftIO $ nullEnv
_ <- clearDivertedVars env
walkExpanded env env env renameEnv cleanupEnv dim True False (List []) code apply
walkExpanded :: Env
-> Env
-> Env
-> Env
-> Env
-> Bool
-> Bool
-> Bool
-> LispVal
-> LispVal
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> IOThrowsError LispVal
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (List l : ls)) apply = do
lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True isQuoted (List []) (List l) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [lst]) (List ls) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((Vector v) : vs)) apply = do
List lst <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List $ elems v) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [asVector lst]) (List vs) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List ((DottedList ds d) : ts)) apply = do
List ls <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) (List ds) apply
l <- walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List []) d apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [DottedList ls l]) (List ts) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList inputIsQuoted (List result) (List (Atom aa : ts)) apply = do
Atom a <- expandAtom renameEnv (Atom aa)
let isQuoted = inputIsQuoted || (a == "quote")
isDefinedAsMacro <- liftIO $ isNamespacedRecBound useEnv macroNamespace a
if isDefinedAsMacro
|| a == aa
|| a == "if"
|| a == "let-syntax"
|| a == "letrec-syntax"
|| a == "define-syntax"
|| a == "define"
|| a == "set!"
|| a == "lambda"
|| a == "quote"
|| a == "expand"
|| a == "string-set!"
|| a == "set-car!"
|| a == "set-cdr!"
|| a == "vector-set!"
|| a == "hash-table-set!"
|| a == "hash-table-delete!"
then walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv
dim startOfList inputIsQuoted (List result) a ts isQuoted isDefinedAsMacro apply
else walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv
dim startOfList inputIsQuoted (List result) (List (Atom a : ts)) apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ isQuoted (List result) (List (t : ts)) apply = do
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False isQuoted (List $ result ++ [t]) (List ts) apply
walkExpanded _ _ _ _ _ _ _ _ result@(List _) (List []) _ = return result
walkExpanded _ _ _ renameEnv _ _ _ _ _ (Atom a) _ = expandAtom renameEnv (Atom a)
walkExpanded _ _ _ _ _ _ _ _ _ transform _ = return transform
walkExpandedAtom :: Env
-> Env
-> Env
-> Env
-> Env
-> Bool
-> Bool
-> Bool
-> LispVal
-> String
-> [LispVal]
-> Bool
-> Bool
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> IOThrowsError LispVal
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True inputIsQuoted (List _)
"let-syntax"
(List _bindings : _body)
False _ apply = do
bodyEnv <- liftIO $ extendEnv useEnv []
bodyRenameEnv <- liftIO $ extendEnv renameEnv []
_ <- loadMacros useEnv bodyEnv (Just bodyRenameEnv) True _bindings
expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body) apply
return $ List [expanded]
walkExpandedAtom _ _ _ _ _ _ True _ _ "let-syntax" ts False _ _ = do
throwError $ BadSpecialForm "Malformed let-syntax expression" $ List (Atom "let-syntax" : ts)
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True inputIsQuoted (List _)
"letrec-syntax"
(List _bindings : _body)
False _ apply = do
bodyEnv <- liftIO $ extendEnv useEnv []
bodyRenameEnv <- liftIO $ extendEnv renameEnv []
_ <- loadMacros bodyEnv bodyEnv (Just bodyRenameEnv) True _bindings
expanded <- walkExpanded defEnv bodyEnv divertEnv bodyRenameEnv cleanupEnv dim True inputIsQuoted (List [Atom "lambda", List []]) (List _body) apply
return $ List [expanded]
walkExpandedAtom _ _ _ _ _ _ True _ _ "letrec-syntax" ts False _ _ = do
throwError $ BadSpecialForm "Malformed letrec-syntax expression" $ List (Atom "letrec-syntax" : ts)
walkExpandedAtom _ useEnv _ renameEnv _ _ True _ (List _)
"define-syntax"
([Atom keyword, (List (Atom "syntax-rules" : Atom ellipsis : (List identifiers : rules)))])
False _ _ = do
renameEnvClosure <- liftIO $ copyEnv renameEnv
_ <- defineNamespacedVar useEnv macroNamespace keyword $ Syntax (Just useEnv) (Just renameEnvClosure) True ellipsis identifiers rules
return $ Nil ""
walkExpandedAtom _ useEnv _ renameEnv _ _ True _ (List _)
"define-syntax"
([Atom keyword, (List (Atom "syntax-rules" : (List identifiers : rules)))])
False _ _ = do
renameEnvClosure <- liftIO $ copyEnv renameEnv
_ <- defineNamespacedVar useEnv macroNamespace keyword $ Syntax (Just useEnv) (Just renameEnvClosure) True "..." identifiers rules
return $ Nil ""
walkExpandedAtom _ useEnv _ renameEnv _ _ True _ (List _)
"define-syntax"
([Atom keyword,
(List [Atom "er-macro-transformer",
(List (Atom "lambda" : List fparams : fbody))])])
False _ _ = do
f <- makeNormalFunc useEnv fparams fbody
_ <- defineNamespacedVar useEnv macroNamespace keyword $ SyntaxExplicitRenaming f
return $ Nil ""
walkExpandedAtom _ _ _ _ _ _ True _ _ "define-syntax" ts False _ _ = do
throwError $ BadSpecialForm "Malformed define-syntax expression" $ List (Atom "define-syntax" : ts)
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
"define"
[Atom var, val]
False _ apply = do
_ <- defineVar renameEnv var $ Atom var
walk
where walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "define", Atom var]) (List [val]) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"define" ts False _ apply = do
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
"set!"
[Atom var, val]
False _ apply = do
isLexicalDef <- liftIO $ isRecBound useEnv var
isAlreadyRenamed <- liftIO $ isRecBound renameEnv var
case (isLexicalDef, isAlreadyRenamed) of
(True, False) -> do
_ <- defineVar renameEnv var $ Atom var
walk
_ -> walk
where
walk = walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List [Atom "set!"]) (List [Atom var, val]) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"set!" ts False _ apply = do
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List _)
"lambda"
(List vars : fbody)
False _ apply = do
env <- liftIO $ extendEnv renameEnv []
renamedVars <- markBoundIdentifiers env cleanupEnv vars []
walkExpanded defEnv useEnv divertEnv env cleanupEnv dim True False (List [Atom "lambda", (renamedVars)]) (List fbody) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result) a@"lambda" ts False _ apply = do
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False False (List $ result ++ [Atom a]) (List ts) apply
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim True _ (List result)
a
ts
False True apply = do
syn <- getNamespacedVar useEnv macroNamespace a
case syn of
Syntax _ (Just renameClosure) definedInMacro ellipsis identifiers rules -> do
List lexpanded <- cleanExpanded defEnv useEnv divertEnv renameEnv renameEnv True False (List []) (List ts) apply
macroTransform defEnv useEnv divertEnv renameClosure cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : lexpanded)) apply ellipsis
Syntax (Just _defEnv) _ definedInMacro ellipsis identifiers rules -> do
macroTransform _defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts)) apply ellipsis
Syntax Nothing _ definedInMacro ellipsis identifiers rules -> do
macroTransform defEnv useEnv divertEnv renameEnv cleanupEnv definedInMacro (List identifiers) rules (List (Atom a : ts)) apply ellipsis
SyntaxExplicitRenaming transformer -> do
erRenameEnv <- liftIO $ nullEnv
expanded <- explicitRenamingTransform
useEnv erRenameEnv (List (Atom a : ts)) transformer apply
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv
dim False False (List result) expanded apply
_ -> throwError $ Default "Unexpected error processing a macro in walkExpandedAtom"
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim _ _ (List result)
a
ts
True _ apply = do
List cleaned <- cleanExpanded
defEnv useEnv divertEnv renameEnv cleanupEnv
dim True
(List []) (List ts)
apply
return $ List $ result ++ (Atom a : cleaned)
walkExpandedAtom defEnv useEnv divertEnv renameEnv cleanupEnv dim _ _ (List result)
a ts isQuoted _ apply = do
walkExpanded defEnv useEnv divertEnv renameEnv cleanupEnv
dim False isQuoted
(List $ result ++ [Atom a]) (List ts)
apply
walkExpandedAtom _ _ _ _ _ _ _ _ _ _ _ _ _ _ = throwError $ Default "Unexpected error in walkExpandedAtom"
markBoundIdentifiers :: Env -> Env -> [LispVal] -> [LispVal] -> IOThrowsError LispVal
markBoundIdentifiers env cleanupEnv (Atom v : vs) renamedVars = do
Atom renamed <- _gensym v
_ <- defineVar env v $ Atom renamed
_ <- defineVar cleanupEnv renamed $ Atom v
markBoundIdentifiers env cleanupEnv vs $ renamedVars ++ [Atom renamed]
markBoundIdentifiers env cleanupEnv (_: vs) renamedVars = markBoundIdentifiers env cleanupEnv vs renamedVars
markBoundIdentifiers _ _ [] renamedVars = return $ List renamedVars
_expandAtom :: Bool -> Env -> LispVal -> IOThrowsError LispVal
_expandAtom isRec renameEnv (Atom a) = do
isDefined <- getVar' renameEnv a
case isDefined of
Just expanded -> do
case isRec of
True -> _expandAtom isRec renameEnv expanded
False -> return expanded
Nothing -> return $ Atom a
_expandAtom _ _ a = return a
recExpandAtom :: Env -> LispVal -> IOThrowsError LispVal
recExpandAtom renameEnv a = _expandAtom True renameEnv a
expandAtom :: Env -> LispVal -> IOThrowsError LispVal
expandAtom renameEnv a = _expandAtom False renameEnv a
cleanExpanded ::
Env
-> Env
-> Env
-> Env
-> Env
-> Bool
-> Bool
-> LispVal
-> LispVal
-> (LispVal -> LispVal -> [LispVal] -> IOThrowsError LispVal)
-> IOThrowsError LispVal
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ (List result) (List (List l : ls)) apply = do
lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True (List []) (List l) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False (List $ result ++ [lst]) (List ls) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ (List result) (List ((Vector v) : vs)) apply = do
List lst <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True (List []) (List $ elems v) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False (List $ result ++ [asVector lst]) (List vs) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ (List result) (List ((DottedList ds d) : ts)) apply = do
List ls <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True (List []) (List ds) apply
l <- cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim True (List []) d apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False (List $ result ++ [DottedList ls l]) (List ts) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim startOfList (List result) (List (Atom a : ts)) apply = do
expanded <- recExpandAtom cleanupEnv $ Atom a
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False (List $ result ++ [expanded]) (List ts) apply
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim _ (List result) (List (t : ts)) apply = do
cleanExpanded defEnv useEnv divertEnv renameEnv cleanupEnv dim False (List $ result ++ [t]) (List ts) apply
cleanExpanded _ _ _ _ _ _ _ result@(List _) (List []) _ = do
return result
cleanExpanded _ _ _ _ _ _ _ _ transform _ = return transform
transformRule :: Env
-> Env
-> Env
-> Env
-> Env
-> Env
-> Bool
-> LispVal
-> String
-> Int
-> [Int]
-> LispVal
-> LispVal
-> IOThrowsError LispVal
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) transform@(List (List l : ts)) = do
let nextHasEllipsis = macroElementMatchesMany transform esym
let level = calcEllipsisLevel nextHasEllipsis ellipsisLevel
let idx = calcEllipsisIndex nextHasEllipsis level ellipsisIndex
if nextHasEllipsis
then do
curT <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym level idx (List []) (List l)
case curT of
Nil _ ->
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
(init ellipsisIndex)
result $ tail ts
List _ -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
idx
(List $ result ++ [curT]) transform
_ -> throwError $ Default "Unexpected error"
else do
lst <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List []) (List l)
case lst of
List _ -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [lst]) (List ts)
Nil _ -> return lst
_ -> throwError $ BadSpecialForm "Macro transform error" $ List [lst, (List l), Number $ toInteger ellipsisLevel]
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) transform@(List ((Vector v) : ts)) = do
let nextHasEllipsis = macroElementMatchesMany transform esym
let level = calcEllipsisLevel nextHasEllipsis ellipsisLevel
let idx = calcEllipsisIndex nextHasEllipsis level ellipsisIndex
if nextHasEllipsis
then do
curT <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym level idx (List []) (List $ elems v)
case curT of
Nil _ ->
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel (init ellipsisIndex) result $ tail ts
List t -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
idx
(List $ result ++ [asVector t]) transform
_ -> throwError $ Default "Unexpected error in transformRule"
else do lst <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List []) (List $ elems v)
case lst of
List l -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [asVector l]) (List ts)
Nil _ -> return lst
_ -> throwError $ BadSpecialForm "transformRule: Macro transform error" $ List [lst, (List [Vector v]), Number $ toInteger ellipsisLevel]
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) transform@(List (dl@(DottedList _ _) : ts)) = do
let nextHasEllipsis = macroElementMatchesMany transform esym
let level = calcEllipsisLevel nextHasEllipsis ellipsisLevel
let idx = calcEllipsisIndex nextHasEllipsis level ellipsisIndex
if nextHasEllipsis
then do
curT <- transformDottedList defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym level idx (List []) (List [dl])
case curT of
Nil _ ->
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel (init ellipsisIndex) result $ tail ts
List t -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
idx
(List $ result ++ t) transform
_ -> throwError $ Default "Unexpected error in transformRule"
else do lst <- transformDottedList defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List []) (List [dl])
case lst of
List l -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ l) (List ts)
Nil _ -> return lst
_ -> throwError $ BadSpecialForm "transformRule: Macro transform error" $ List [lst, (List [dl]), Number $ toInteger ellipsisLevel]
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) transform@(List (Atom a : ts)) = do
Bool isIdent <- findAtom (Atom a) identifiers
isDefined <- liftIO $ isBound localEnv a
if isIdent
then literalHere
else do
if hasEllipsis
then ellipsisHere isDefined
else noEllipsis isDefined
where
literalHere = do
expanded <- transformLiteralIdentifier defEnv outerEnv divertEnv renameEnv dim a
if hasEllipsis
then do
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [expanded]) (List $ tail ts)
else do
continueTransformWith $ result ++ [expanded]
appendNil d (Bool isImproperPattern) (Bool isImproperInput) =
case d of
List lst -> if isImproperPattern && not isImproperInput
then List $ lst ++ [List []]
else List lst
_ -> d
appendNil d _ _ = d
loadNamespacedBool namespc = do
val <- getNamespacedVar' localEnv namespc a
case val of
Just b -> return b
Nothing -> return $ Bool False
hasEllipsis = macroElementMatchesMany transform esym
ellipsisHere isDefined = do
if isDefined
then do
isImproperPattern <- loadNamespacedBool 'p'
isImproperInput <- loadNamespacedBool 'i'
var <- getVar localEnv a
case var of
List _ -> do case (appendNil (Matches.getData var ellipsisIndex) isImproperPattern isImproperInput) of
List aa -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ aa) (List $ tail ts)
_ ->
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex result $ tail ts
Nil "" ->
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex result $ tail ts
v@(_) -> transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [v]) (List $ tail ts)
else
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) (List $ tail ts)
noEllipsis isDefined = do
isImproperPattern <- loadNamespacedBool 'p'
isImproperInput <- loadNamespacedBool 'i'
t <- if (isDefined)
then do
var <- getVar localEnv a
case (var) of
Nil "" -> do
wasPair <- getNamespacedVar localEnv
'_'
a
case wasPair of
Bool True -> return $ Nil "var (pair) not defined in pattern"
_ -> return $ Nil "var not defined in pattern"
Nil input -> do v <- getVar outerEnv input
return v
List v -> do
if ellipsisLevel > 0
then
return $ appendNil (Matches.getData var ellipsisIndex)
isImproperPattern
isImproperInput
else if length v > 0
then return var
else return $ Nil ""
_ -> if ellipsisLevel > 0
then
throwError $ Default "Unexpected error processing data in transformRule"
else return var
else do
alreadyRenamed <- getNamespacedVar' localEnv 'r' a
case alreadyRenamed of
Just renamed -> return renamed
Nothing -> do
Atom renamed <- _gensym a
_ <- defineNamespacedVar localEnv 'r' a $ Atom renamed
_ <- defineNamespacedVar renameEnv 'r' a $ Atom renamed
_ <- defineVar cleanupEnv renamed $ Atom a
_ <- defineVar (renameEnv) renamed $ Atom a
return $ Atom renamed
case t of
Nil "var not defined in pattern" ->
if ellipsisLevel > 0
then return t
else continueTransformWith result
Nil "var (pair) not defined in pattern" ->
if ellipsisLevel > 0
then return t
else continueTransformWith $ result ++ [List []]
Nil _ -> return t
List l -> do
if (eqVal isImproperPattern $ Bool True) && (eqVal isImproperInput $ Bool True)
then continueTransformWith $ result ++ (buildImproperList l)
else continueTransformWith $ result ++ [t]
_ -> continueTransformWith $ result ++ [t]
buildImproperList lst
| length lst > 1 = [DottedList (init lst) (last lst)]
| otherwise = lst
continueTransformWith results =
transformRule defEnv outerEnv divertEnv
localEnv
renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
ellipsisIndex
(List $ results)
(List ts)
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) (List (t : ts)) = do
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [t]) (List ts)
transformRule _ _ _ _ _ _ _ _ _ _ _ result@(List _) (List []) = do
return result
transformRule defEnv outerEnv divertEnv localEnv renameEnv _ dim identifiers esym _ _ _ (Atom transform) = do
Bool isIdent <- findAtom (Atom transform) identifiers
isPattVar <- liftIO $ isRecBound localEnv transform
if isPattVar && not isIdent
then getVar localEnv transform
else transformLiteralIdentifier defEnv outerEnv divertEnv renameEnv dim transform
transformRule _ _ _ _ _ _ _ _ _ _ _ _ transform = return transform
transformLiteralIdentifier :: Env -> Env -> Env -> Env -> Bool -> String -> IOThrowsError LispVal
transformLiteralIdentifier defEnv outerEnv divertEnv renameEnv definedInMacro transform = do
isInDef <- liftIO $ isRecBound defEnv transform
isRenamed <- liftIO $ isRecBound renameEnv transform
if (isInDef && not definedInMacro) || (isInDef && definedInMacro && not isRenamed)
then do
value <- getVar defEnv transform
Atom renamed <- _gensym transform
_ <- defineVar divertEnv renamed value
List diverted <- getNamespacedVar outerEnv ' ' "diverted"
_ <- setNamespacedVar outerEnv ' ' "diverted" $
List (diverted ++ [List [Atom renamed, Atom transform]])
return $ Atom renamed
else do
return $ Atom transform
transformDottedList :: Env -> Env -> Env -> Env -> Env -> Env -> Bool -> LispVal -> String -> Int -> [Int] -> LispVal -> LispVal -> IOThrowsError LispVal
transformDottedList defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List result) (List (DottedList ds d : ts)) = do
lsto <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List []) (List ds)
case lsto of
List lst -> do
r <- transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers
esym
ellipsisLevel
ellipsisIndex
(List [])
(List [d, Atom esym])
case r of
List [] ->
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [List lst]) (List ts)
Nil _ ->
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex (List $ result ++ [List lst]) (List ts)
List rst -> do
transformRule defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex
(buildTransformedCode result lst rst) (List ts)
_ -> throwError $ BadSpecialForm "Macro transform error processing pair" $ DottedList ds d
Nil _ -> return $ Nil ""
_ -> throwError $ BadSpecialForm "Macro transform error processing pair" $ DottedList ds d
where
buildTransformedCode results ps p = do
case p of
[List []] -> List $ results ++ [List ps]
[List ls] -> List $ results ++ [List $ ps ++ ls]
[l] -> List $ results ++ [DottedList ps l]
ls -> do
case last ls of
List [] -> List $ results ++ [List $ ps ++ init ls]
List lls -> List $ results ++ [List $ ps ++ (init ls) ++ lls]
t -> List $ results ++ [DottedList (ps ++ init ls) t]
transformDottedList _ _ _ _ _ _ _ _ _ _ _ _ _ = throwError $ Default "Unexpected error in transformDottedList"
continueTransform :: Env -> Env -> Env -> Env -> Env -> Env -> Bool -> LispVal -> String -> Int -> [Int] -> [LispVal] -> [LispVal] -> IOThrowsError LispVal
continueTransform defEnv outerEnv divertEnv localEnv renameEnv cleanupEnv dim identifiers esym ellipsisLevel ellipsisIndex result remaining = do
if not (null remaining)
then transformRule defEnv outerEnv divertEnv
localEnv
renameEnv
cleanupEnv dim identifiers
esym
ellipsisLevel
ellipsisIndex
(List result)
(List $ remaining)
else if length result > 0
then return $ List result
else if ellipsisLevel > 0
then return $ Nil ""
else return $ List []
findAtom :: LispVal -> LispVal -> IOThrowsError LispVal
findAtom (Atom target) (List (Atom a : as)) = do
if target == a
then return $ Bool True
else findAtom (Atom target) (List as)
findAtom _ (List (badtype : _)) = throwError $ TypeMismatch "symbol" badtype
findAtom _ _ = return $ Bool False
calcEllipsisLevel :: Bool -> Int -> Int
calcEllipsisLevel nextHasEllipsis ellipsisLevel =
if nextHasEllipsis then ellipsisLevel + 1
else ellipsisLevel
calcEllipsisIndex :: Bool -> Int -> [Int] -> [Int]
calcEllipsisIndex nextHasEllipsis ellipsisLevel ellipsisIndex =
if nextHasEllipsis
then if (length ellipsisIndex == ellipsisLevel)
then do
let l = splitAt (ellipsisLevel 1) ellipsisIndex
(fst l) ++ [(head (snd l)) + 1]
else ellipsisIndex ++ [0]
else ellipsisIndex
asVector :: [LispVal] -> LispVal
asVector lst = (Vector $ (listArray (0, length lst 1)) lst)
loadMacros :: Env
-> Env
-> Maybe Env
-> Bool
-> [LispVal]
-> IOThrowsError LispVal
loadMacros e be Nothing dim
(List
[Atom keyword,
(List (Atom "syntax-rules" :
Atom ellipsis :
(List identifiers : rules)))] :
bs) = do
_ <- defineNamespacedVar be macroNamespace keyword $
Syntax (Just e) Nothing dim ellipsis identifiers rules
loadMacros e be Nothing dim bs
loadMacros e be Nothing dim
(List
[Atom keyword,
(List (Atom "syntax-rules" :
(List identifiers : rules)))] :
bs) = do
_ <- defineNamespacedVar be macroNamespace keyword $
Syntax (Just e) Nothing dim "..." identifiers rules
loadMacros e be Nothing dim bs
loadMacros e be Nothing dim
(List
[Atom keyword, (List [Atom "er-macro-transformer",
(List (Atom "lambda" : List fparams : fbody))])]
: bs) = do
f <- makeNormalFunc e fparams fbody
_ <- defineNamespacedVar be macroNamespace keyword $ SyntaxExplicitRenaming f
loadMacros e be Nothing dim bs
loadMacros e be (Just re) dim
args@(List [Atom keyword,
(List (Atom syntaxrules : spec))] :
bs) = do
Atom exKeyword <- expandAtom re (Atom keyword)
exSynRules <- expandAtom re (Atom syntaxrules)
case (exSynRules, spec) of
(Atom "syntax-rules",
(Atom ellipsis :
(List identifiers : rules))) -> do
_ <- defineNamespacedVar be macroNamespace exKeyword $
Syntax (Just e) (Just re) dim ellipsis identifiers rules
loadMacros e be (Just re) dim bs
(Atom "syntax-rules",
(List identifiers : rules)) -> do
_ <- defineNamespacedVar be macroNamespace exKeyword $
Syntax (Just e) (Just re) dim "..." identifiers rules
loadMacros e be (Just re) dim bs
(Atom "er-macro-transformer",
[List (Atom _ : List fparams : fbody)]) -> do
f <- makeNormalFunc e fparams fbody
_ <- defineNamespacedVar be macroNamespace exKeyword $ SyntaxExplicitRenaming f
loadMacros e be (Just re) dim bs
_ -> throwError $ BadSpecialForm "Unable to evaluate form w/re" $ List args
loadMacros _ _ _ _ [] = return $ Nil ""
loadMacros _ _ _ _ form = throwError $ BadSpecialForm "Unable to evaluate form" $ List form