atomo programming language — http://atomo-lang.org/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | module Atomo.Parser.Expand (doPragmas, macroExpand, nextPhase) where
import Control.Monad.State
import Atomo.Environment
import Atomo.Helpers
import Atomo.Method (addMethod, lookupMap)
import Atomo.Pattern (match)
import Atomo.Types
gensym :: Char
gensym = '!'
nextPhase :: [Expr] -> VM [Expr]
nextPhase es = do
mapM_ doPragmas es
mapM macroExpand es
doPragmas :: Expr -> VM ()
doPragmas (EDispatch { eMessage = em }) =
pragmas em
where
pragmas (Single { mTarget = t }) =
doPragmas t
pragmas (Keyword { mTargets = ts }) =
mapM_ doPragmas ts
doPragmas (EDefine { eExpr = e }) = do
doPragmas e
doPragmas (ESet { eExpr = e }) = do
doPragmas e
doPragmas (EBlock { eContents = es }) = do
mapM_ doPragmas es
doPragmas (EList { eContents = es }) = do
mapM_ doPragmas es
doPragmas (ETuple { eContents = es }) = do
mapM_ doPragmas es
doPragmas (EMacro { emPattern = p, eExpr = e }) =
addMacro p e
doPragmas (EParticle { eParticle = ep }) =
case ep of
Keyword { mTargets = mes } ->
forM_ mes $ \me ->
case me of
Nothing -> return ()
Just e -> doPragmas e
Single { mTarget = Just e } ->
doPragmas e
_ -> return ()
doPragmas (EMatch { eTarget = e, eBranches = bs }) = do
doPragmas e
forM_ bs (doPragmas . snd)
doPragmas (EOperator {}) = return ()
doPragmas (EPrimitive {}) = return ()
doPragmas (EForMacro { eExpr = e }) = do
env <- gets (psEnvironment . parserState)
macroExpand e >>= withTop env . eval
return ()
doPragmas (ETop {}) = return ()
doPragmas (EVM {}) = return ()
-- TODO: follow through EQuote into EUnquote
doPragmas (EQuote {}) = return ()
doPragmas (EUnquote {}) = return ()
doPragmas (ESetDynamic { eExpr = e }) =
doPragmas e
doPragmas (EDefineDynamic { eExpr = e }) =
doPragmas e
doPragmas (ENewDynamic { eBindings = bs, eExpr = e }) = do
mapM_ (\(_, b) -> doPragmas b) bs
doPragmas e
doPragmas (EGetDynamic {}) = return ()
doPragmas (EMacroQuote {}) = return ()
-- | Defines a macro, given its pattern and expression.
addMacro :: Message Pattern -> Expr -> VM ()
addMacro p e =
modify $ \env -> env
{ parserState = (parserState env)
{ psMacros = withMacro (psMacros (parserState env))
}
}
where
withMacro ms =
case p of
Single {} ->
(addMethod (Macro p e) (fst ms), snd ms)
Keyword {} ->
(fst ms, addMethod (Macro p e) (snd ms))
modifyPS :: (ParserState -> ParserState) -> VM ()
modifyPS f =
modify $ \e -> e
{ parserState = f (parserState e)
}
getPS :: VM ParserState
getPS = gets parserState
-- | Go through an expression recursively expanding macros. A dispatch
-- expression is checked to see if a macro was defined for it; if a macro is
-- found, its targets are sent to the macro method (unexpanded), and the
-- macro's result is expanded.
--
-- Every other expression just recursively calls macroExpand on any
-- sub-expressions.
macroExpand :: Expr -> VM Expr
macroExpand d@(EDispatch { eMessage = em }) = do
mm <- findMacro msg
case mm of
Just m -> do
modifyPS $ \ps -> ps { psClock = psClock ps + 1 }
eb <- gensyms (mExpr m) >>= macroExpand
Expression ne <-
runMethod (m { mExpr = eb }) msg
>>= findExpression
gensyms ne >>= macroExpand
Nothing -> do
nem <- expanded em
return d { eMessage = nem }
where
expanded s@(Single { mTarget = t }) = do
nt <- macroExpand t
return s { mTarget = nt }
expanded k@(Keyword { mTargets = ts }) = do
nts <- mapM macroExpand ts
return k { mTargets = nts }
msg =
case em of
Single i n t os -> Single i n (Expression t) (map exprOpt os)
Keyword i ns ts os -> Keyword i ns (map Expression ts) (map exprOpt os)
exprOpt (Option i n e) = Option i n (Expression e)
macroExpand e@(EMacroQuote { eName = n, eRaw = r, eFlags = fs }) = do
t <- gets (psEnvironment . parserState)
liftM (EPrimitive (eLocation e)) . dispatch $
keyword'
["quote", "as"]
[t, string r, particle n]
[option "flags" (list (map Character fs))]
macroExpand d@(EDefine { eExpr = e }) = do
e' <- macroExpand e
return d { eExpr = e' }
macroExpand s@(ESet { eExpr = e }) = do
e' <- macroExpand e
return s { eExpr = e' }
macroExpand b@(EBlock { eContents = es }) = do
nes <- mapM macroExpand es
return b { eContents = nes }
macroExpand l@(EList { eContents = es }) = do
nes <- mapM macroExpand es
return l { eContents = nes }
macroExpand t@(ETuple { eContents = es }) = do
nes <- mapM macroExpand es
return t { eContents = nes }
macroExpand p@(EParticle { eParticle = ep }) = do
nos <- forM (mOptionals ep) $ \(Option i n me) -> do
ne <- maybe (return Nothing) (liftM Just . macroExpand) me
return (Option i n ne)
case ep of
Keyword { mNames = ns, mTargets = mes } -> do
nmes <- forM mes $ \me ->
case me of
Nothing -> return Nothing
Just e -> liftM Just (macroExpand e)
return p { eParticle = keyword' ns nmes nos }
Single { mName = n, mTarget = Just e } -> do
ne <- macroExpand e
return p { eParticle = single' n (Just ne) nos }
_ -> return p
macroExpand s@(ESetDynamic { eExpr = e }) = do
e' <- macroExpand e
return s { eExpr = e' }
macroExpand d@(EDefineDynamic { eExpr = e }) = do
e' <- macroExpand e
return d { eExpr = e' }
macroExpand n@(ENewDynamic { eBindings = bs, eExpr = e }) = do
bs' <- mapM (\(p, b) -> macroExpand b >>= \nb -> return (p, nb)) bs
e' <- macroExpand e
return n { eBindings = bs', eExpr = e' }
macroExpand m@(EMatch { eTarget = t, eBranches = bs }) = do
nt <- macroExpand t
nbs <- forM bs $ \(p, e) -> do
ne <- macroExpand e
return (p, ne)
return m { eTarget = nt, eBranches = nbs }
macroExpand m@(EMacro {}) = return m
macroExpand e@(EGetDynamic {}) = return e
macroExpand e@(EOperator {}) = return e
macroExpand e@(EPrimitive {}) = return e
macroExpand e@(EForMacro {}) = return e
macroExpand e@(ETop {}) = return e
macroExpand e@(EVM {}) = return e
macroExpand e@(EQuote {}) = expandQuote e
macroExpand e@(EUnquote {}) = return e
expandQuote :: Expr -> VM Expr
expandQuote = throughQuotes 0 $ \n e ->
case n of
0 -> macroExpand e
_ -> return e
gensyms :: Expr -> VM Expr
gensyms = throughQuotes 0 $ \_ e ->
case e of
EDispatch { eMessage = m@(Single { mName = x:xs }) }
| x == gensym -> do
c <- gets (psClock . parserState)
return e
{ eMessage = single'
(xs ++ ":" ++ show c)
(mTarget m)
(mOptionals m)
}
_ -> return e
throughQuotes :: Int -> (Int -> Expr -> VM Expr) -> Expr -> VM Expr
throughQuotes 0 f u@(EUnquote { eExpr = e }) = do
ne <- f 0 e
return u { eExpr = ne }
throughQuotes n f u@(EUnquote { eExpr = a }) = do
ne <- throughQuotes (n - 1) f a
f n u { eExpr = ne }
-- don't expand through definitions, as gensyms in those
-- are likely used elsewhere where they'll be expanded
throughQuotes n f d@(EDefine {}) = f n d
throughQuotes n f s@(ESet { ePattern = p, eExpr = e }) = do
np <- expandPattern p
ne <- throughQuotes n f e
f n s { ePattern = np, eExpr = ne }
throughQuotes n f d@(EDispatch { eMessage = m@(Keyword {}) }) = do
nts <- mapM (throughQuotes n f) (mTargets m)
f n d { eMessage = m { mTargets = nts } }
throughQuotes n f d@(EDispatch { eMessage = m@(Single {}) }) = do
nt <- throughQuotes n f (mTarget m)
f n d { eMessage = m { mTarget = nt } }
throughQuotes n f b@(EBlock { eArguments = ps, eContents = es }) = do
nps <- mapM expandPattern ps
nes <- mapM (throughQuotes n f) es
f n b { eArguments = nps, eContents = nes }
throughQuotes n f l@(EList { eContents = es }) = do
nes <- mapM (throughQuotes n f) es
f n l { eContents = nes }
throughQuotes n f t@(ETuple { eContents = es }) = do
nes <- mapM (throughQuotes n f) es
f n t { eContents = nes }
throughQuotes n f m@(EMacro { eExpr = e }) = do
ne <- throughQuotes n f e
f n m { eExpr = ne }
throughQuotes n f p@(EParticle { eParticle = m@(Keyword { mTargets = mes }) }) = do
nmes <- forM mes $ maybe (return Nothing) (liftM Just . throughQuotes n f)
f n p { eParticle = m { mTargets = nmes } }
throughQuotes n f p@(EParticle { eParticle = m@(Single { mTarget = me }) }) = do
nme <- maybe (return Nothing) (liftM Just . throughQuotes n f) me
f n p { eParticle = m { mTarget = nme } }
throughQuotes n f s@(ESetDynamic { eExpr = e }) = do
e' <- throughQuotes n f e
f n s { eExpr = e' }
throughQuotes n f d@(EDefineDynamic { eExpr = e }) = do
e' <- throughQuotes n f e
f n d { eExpr = e' }
throughQuotes n f d@(ENewDynamic { eBindings = bs, eExpr = e }) = do
nbs <- mapM (\(p, b) -> f n b >>= \nb -> return (p, nb)) bs
ne <- throughQuotes n f e
f n d { eBindings = nbs, eExpr = ne }
throughQuotes n f q@(EQuote { eExpr = e }) = do
ne <- throughQuotes (n + 1) f e
f (n + 1) q { eExpr = ne }
throughQuotes n f m@(EMatch { eTarget = t, eBranches = bs }) = do
nt <- throughQuotes n f t
nbs <- mapM (\(p, b) -> f n b >>= \nb -> return (p, nb)) bs
f n m { eTarget = nt, eBranches = nbs }
throughQuotes n f e = f n e
expandPattern :: Pattern -> VM Pattern
expandPattern (PNamed n p)
| head n == gensym = do
c <- gets (psClock . parserState)
np <- expandPattern p
return (PNamed (tail n ++ ":" ++ show c) np)
| otherwise = liftM (PNamed n) (expandPattern p)
expandPattern (PHeadTail h t) =
liftM2 PHeadTail (expandPattern h) (expandPattern t)
expandPattern (PList ps) =
liftM PList (mapM expandPattern ps)
expandPattern (PTuple ps) =
liftM PTuple (mapM expandPattern ps)
expandPattern (PMessage (m@(Single { mTarget = t }))) = do
nt <- expandPattern t
return $ PMessage m { mTarget = nt }
expandPattern (PMessage (m@(Keyword { mTargets = ts }))) = do
nts <- mapM expandPattern ts
return $ PMessage m { mTargets = nts }
expandPattern (PInstance p) =
liftM PInstance (expandPattern p)
expandPattern (PStrict p) =
liftM PStrict (expandPattern p)
expandPattern (PVariable p) =
liftM PVariable (expandPattern p)
expandPattern (PExpr p) =
liftM PExpr (expandQuote p)
expandPattern (PPMKeyword ns ps) =
liftM (PPMKeyword ns) (mapM expandPattern ps)
expandPattern p = return p
-- | find a findMacro method for message `m' on object `o'
findMacro :: Message Value -> VM (Maybe Method)
findMacro m = do
ids <- gets primitives
ms <- methods m
return $ maybe Nothing (firstMatch ids m) (lookupMap (mID m) ms)
where
methods (Single {}) = liftM (fst . psMacros) getPS
methods (Keyword {}) = liftM (snd . psMacros) getPS
firstMatch _ _ [] = Nothing
firstMatch ids' m' (mt:mts)
| match ids' Nothing (PMessage (mPattern mt)) (Message m') =
Just mt
| otherwise = firstMatch ids' m' mts
|