| 1 | {-# OPTIONS_GHC -fglasgow-exts -fallow-overlapping-instances #-} |
|---|
| 2 | |
|---|
| 3 | {-| |
|---|
| 4 | Common operations on Eval monad. |
|---|
| 5 | |
|---|
| 6 | > One Ring to rule them all, |
|---|
| 7 | > One Ring to find them, |
|---|
| 8 | > One Ring to bring them all |
|---|
| 9 | > and in the darkness bind them... |
|---|
| 10 | |
|---|
| 11 | Note that the actual monads are defined elsewhere -- try looking at |
|---|
| 12 | "Pugs.AST.SIO" and "Pugs.AST.Internals". |
|---|
| 13 | -} |
|---|
| 14 | |
|---|
| 15 | module Pugs.Monads ( |
|---|
| 16 | ApplyKind(..), |
|---|
| 17 | |
|---|
| 18 | enterLValue, enterRValue, |
|---|
| 19 | enterLex, enterContext, enterEvalContext, enterPackage, enterCaller, |
|---|
| 20 | enterGiven, enterWhen, enterLoop, enterGather, genSymPrim, genSymCC, |
|---|
| 21 | enterBlock, enterSub, |
|---|
| 22 | evalVal, |
|---|
| 23 | |
|---|
| 24 | enterFrame, assertFrame, emptyFrames, |
|---|
| 25 | |
|---|
| 26 | reclosePad, recloseCode, recloseVal, |
|---|
| 27 | |
|---|
| 28 | MaybeT, runMaybeT |
|---|
| 29 | ) where |
|---|
| 30 | import Pugs.Internals |
|---|
| 31 | import Pugs.AST |
|---|
| 32 | import Pugs.Types |
|---|
| 33 | import qualified Data.Set as Set |
|---|
| 34 | |
|---|
| 35 | newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } |
|---|
| 36 | |
|---|
| 37 | instance (Monad m) => Monad (MaybeT m) where |
|---|
| 38 | (MaybeT mon) >>= f = |
|---|
| 39 | MaybeT (mon >>= maybe (return Nothing) (runMaybeT . f)) |
|---|
| 40 | return = MaybeT . return . Just |
|---|
| 41 | |
|---|
| 42 | instance MonadTrans MaybeT where |
|---|
| 43 | lift mon = MaybeT (mon >>= return . Just) |
|---|
| 44 | |
|---|
| 45 | instance (MonadIO m) => MonadIO (MaybeT m) where |
|---|
| 46 | liftIO ma = MaybeT $ do |
|---|
| 47 | a <- liftIO ma |
|---|
| 48 | return (Just a) |
|---|
| 49 | |
|---|
| 50 | instance (Monad m) => MonadPlus (MaybeT m) where |
|---|
| 51 | mzero = MaybeT (return Nothing) |
|---|
| 52 | mplus (MaybeT a) (MaybeT b) = MaybeT $ do |
|---|
| 53 | ma <- a |
|---|
| 54 | case ma of |
|---|
| 55 | Nothing -> b |
|---|
| 56 | _ -> return ma |
|---|
| 57 | |
|---|
| 58 | {-| |
|---|
| 59 | Perform the given evaluation in an /LValue/ context. |
|---|
| 60 | -} |
|---|
| 61 | enterLValue :: Eval a -> Eval a |
|---|
| 62 | enterLValue = local (\e -> e{ envLValue = True }) |
|---|
| 63 | {-| |
|---|
| 64 | Perform the given evaluation in an /RValue/ (i.e. non-/LValue/) context. |
|---|
| 65 | -} |
|---|
| 66 | enterRValue :: Eval a -> Eval a |
|---|
| 67 | enterRValue = local (\e -> e{ envLValue = False }) |
|---|
| 68 | |
|---|
| 69 | {-| |
|---|
| 70 | Create a new lexical scope by applying the list of 'Pad'-transformers |
|---|
| 71 | (which install new bindings), then perform the specified evaluation in that |
|---|
| 72 | new scope. |
|---|
| 73 | |
|---|
| 74 | (Subsequent chained 'Eval's do /not/ see this new scope.) |
|---|
| 75 | -} |
|---|
| 76 | enterLex :: [PadMutator] -- ^ Transformations on current 'Pad' to produce the |
|---|
| 77 | -- new 'Pad'. |
|---|
| 78 | -> Eval a -- ^ Evaluation to be performed in the new scope |
|---|
| 79 | -> Eval a -- ^ Resulting evaluation (lexical scope enter & exit |
|---|
| 80 | -- are encapsulated) |
|---|
| 81 | enterLex newSyms = local (\e -> e{ envLexical = combine newSyms (envLexical e) }) |
|---|
| 82 | |
|---|
| 83 | {-| |
|---|
| 84 | Perform the specified evaluation in the specified (Perl 6) context ('Cxt'). |
|---|
| 85 | |
|---|
| 86 | (Subsequent chained 'Eval's do /not/ see this new scope.) |
|---|
| 87 | -} |
|---|
| 88 | enterContext :: Cxt -> Eval a -> Eval a |
|---|
| 89 | enterContext cxt = local (\e -> e{ envContext = cxt }) |
|---|
| 90 | |
|---|
| 91 | {-| |
|---|
| 92 | Evaluate the specified expression in the specified (Perl 6) context ('Cxt'). |
|---|
| 93 | |
|---|
| 94 | (Subsequent chained 'Eval's do /not/ see this new scope.) |
|---|
| 95 | -} |
|---|
| 96 | enterEvalContext :: Cxt -> Exp -> Eval Val |
|---|
| 97 | enterEvalContext cxt = enterContext cxt . evalExp |
|---|
| 98 | |
|---|
| 99 | {-| |
|---|
| 100 | Perform the specified evaluation in the specified package. |
|---|
| 101 | |
|---|
| 102 | (Subsequent chained 'Eval's do /not/ see this package.) |
|---|
| 103 | -} |
|---|
| 104 | enterPackage :: ByteString -> Eval a -> Eval a |
|---|
| 105 | enterPackage pkg = local (\e -> e{ envPackage = cast pkg }) |
|---|
| 106 | |
|---|
| 107 | {-| |
|---|
| 108 | Enter a new environment and mark the previous one as 'Caller'. |
|---|
| 109 | Also swap in the new one's lexical environment. |
|---|
| 110 | -} |
|---|
| 111 | enterCaller :: Eval a -> Eval a |
|---|
| 112 | enterCaller = local envEnterCaller |
|---|
| 113 | |
|---|
| 114 | envEnterCaller :: Env -> Env |
|---|
| 115 | envEnterCaller env = env |
|---|
| 116 | { envCaller = Just env |
|---|
| 117 | , envFrames = FrameRoutine `Set.insert` envFrames env |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | {-| |
|---|
| 121 | Register the fact that we are inside a specially marked control block. |
|---|
| 122 | -} |
|---|
| 123 | enterFrame :: Frame -> Eval a -> Eval a |
|---|
| 124 | enterFrame f = local (\e -> e{ envFrames = f `Set.insert` envFrames e}) |
|---|
| 125 | |
|---|
| 126 | enterGather, enterLoop, enterGiven :: Eval Val -> Eval Val |
|---|
| 127 | enterGather = enterFrame FrameGather |
|---|
| 128 | enterLoop = enterFrame FrameLoop |
|---|
| 129 | enterGiven = id |
|---|
| 130 | |
|---|
| 131 | assertFrame :: Frame -> Eval a -> Eval a |
|---|
| 132 | assertFrame f action = do |
|---|
| 133 | frames <- asks envFrames |
|---|
| 134 | if Set.member f frames |
|---|
| 135 | then action |
|---|
| 136 | else fail ("Cannot use this control structure outside a '" ++ (map toLower (drop 5 (show f))) ++ "' structure") |
|---|
| 137 | |
|---|
| 138 | emptyFrames :: Set Frame |
|---|
| 139 | emptyFrames = Set.empty |
|---|
| 140 | |
|---|
| 141 | {-| |
|---|
| 142 | Note that this function is /not/ responsible for performing the actual @when@ |
|---|
| 143 | test, nor is it responsible for adding the implicit @break@ to the end of the |
|---|
| 144 | @when@'s block--those are already taken care of by 'Pugs.Eval.reduce' |
|---|
| 145 | (see the entry for @('Syn' \"when\" ... )@). |
|---|
| 146 | -} |
|---|
| 147 | enterWhen :: Eval Val -- ^ The @when@'s body block, as an evaluation |
|---|
| 148 | -> Eval Val |
|---|
| 149 | enterWhen action = do |
|---|
| 150 | rv <- enterFrame FrameWhen action |
|---|
| 151 | case rv of |
|---|
| 152 | VControl (ControlWhen WhenContinue) -> retEmpty |
|---|
| 153 | VControl (ControlWhen WhenBreak) -> retShiftEmpty |
|---|
| 154 | _ -> retShift rv |
|---|
| 155 | |
|---|
| 156 | {-| |
|---|
| 157 | Generate a new Perl 6 operation from a Haskell function, give it a name, and |
|---|
| 158 | generate a @('Pad' -> 'Pad')@ transformer that can be used to install it into |
|---|
| 159 | a pad. |
|---|
| 160 | |
|---|
| 161 | This transformer is passed into a given \'action\' function, which is |
|---|
| 162 | expected to apply the pad-transformer (e.g. in a new lexical scope), then |
|---|
| 163 | perform some evaluation in that scope. |
|---|
| 164 | |
|---|
| 165 | Most of the time, this \'action\' is an anonymous function that passes its |
|---|
| 166 | argument into 'enterLex'. |
|---|
| 167 | -} |
|---|
| 168 | genSymPrim :: (MonadSTM m) |
|---|
| 169 | => String -- ^ Name installed in 'Pad' |
|---|
| 170 | -- (must have leading @&@ sigil) |
|---|
| 171 | -> ([Val] -> Eval Val) -- ^ The actual primitive to wrap |
|---|
| 172 | -> (PadMutator -> m t) -- ^ A (lambda) function that the 'Pad' |
|---|
| 173 | -- transformer is given to |
|---|
| 174 | -> m t -- ^ Result of passing the pad-transformer to the \'action\' |
|---|
| 175 | genSymPrim symName@('&':name) prim action = do |
|---|
| 176 | newSym <- genSym (cast symName) . codeRef $ mkPrim |
|---|
| 177 | { subName = cast name |
|---|
| 178 | , subBody = Prim prim |
|---|
| 179 | } |
|---|
| 180 | action newSym |
|---|
| 181 | genSymPrim _ _ _ = error "need a &name" |
|---|
| 182 | |
|---|
| 183 | {-| |
|---|
| 184 | Generate a Perl 6 primitive that, when called, will activate the /current/ |
|---|
| 185 | continuation (i.e. one that can be used to immediately break out of whatever |
|---|
| 186 | evaluation we are about to perform). This is great for @&last@ and the like. |
|---|
| 187 | |
|---|
| 188 | This produces a pad-transformer @('Pad' -> 'Pad')@. This transformer is given |
|---|
| 189 | to an \'action\' function, which is expected to apply it (e.g. in a lexical |
|---|
| 190 | scope), then perform some evaluation in that scope. |
|---|
| 191 | -} |
|---|
| 192 | genSymCC :: String -- ^ Name of the primitive in the symbol table ('Pad'). |
|---|
| 193 | -> (PadMutator -> Eval Val) -- ^ An \'action\' function that will |
|---|
| 194 | -- take the pad-transformer and use |
|---|
| 195 | -- it to perform some evaluation |
|---|
| 196 | -> Eval Val -- ^ Result of passing the pad-transformer to the |
|---|
| 197 | -- \'action\' |
|---|
| 198 | genSymCC symName action = callCC $ \esc -> do |
|---|
| 199 | genSymPrim symName (const $ esc undef) action |
|---|
| 200 | |
|---|
| 201 | {-| |
|---|
| 202 | Used by 'Pugs.Eval.reduce' when evaluating @('Syn' \"block\" ... )@ |
|---|
| 203 | expressions. |
|---|
| 204 | -} |
|---|
| 205 | enterBlock :: Eval Val -> Eval Val |
|---|
| 206 | enterBlock action = do |
|---|
| 207 | local (\e -> e{ envLexPads = (PRuntime emptyPad:envLexPads e) }) action |
|---|
| 208 | |
|---|
| 209 | recloseLexPad :: LexPad -> STM LexPad |
|---|
| 210 | recloseLexPad (PCompiling tv) = do |
|---|
| 211 | pad <- readMPad tv |
|---|
| 212 | return (PRuntime pad) |
|---|
| 213 | recloseLexPad lpad = return lpad |
|---|
| 214 | |
|---|
| 215 | recloseExp :: Exp -> STM Exp |
|---|
| 216 | recloseExp (Val val) = fmap Val (recloseVal val) |
|---|
| 217 | recloseExp exp = return exp |
|---|
| 218 | |
|---|
| 219 | recloseVal :: Val -> STM Val |
|---|
| 220 | recloseVal (VRef ref) = do |
|---|
| 221 | fmap VRef (recloseRef ref) |
|---|
| 222 | recloseVal (VCode code) = do |
|---|
| 223 | fmap VCode (recloseCode code) |
|---|
| 224 | recloseVal (VList list) = do |
|---|
| 225 | fmap VList (mapM recloseVal list) |
|---|
| 226 | recloseVal val = return val |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | recloseTraitBlocks :: TraitBlocks -> STM TraitBlocks |
|---|
| 230 | recloseTraitBlocks (MkTraitBlocks a b c d e f g h i j k) = do |
|---|
| 231 | [a', b', c', d', e', f', g', h', i', j', k'] <- mapM (mapM recloseCode) [a, b, c, d, e, f, g, h, i, j, k] |
|---|
| 232 | return $ MkTraitBlocks a' b' c' d' e' f' g' h' i' j' k' |
|---|
| 233 | |
|---|
| 234 | recloseCode :: VCode -> STM VCode |
|---|
| 235 | recloseCode vcode |
|---|
| 236 | | Nothing <- subStarted vcode = do |
|---|
| 237 | -- , subType vcode /= SubPrim = do |
|---|
| 238 | outers' <- mapM recloseLexPad (subOuterPads vcode) |
|---|
| 239 | inner' <- reclosePad (subInnerPad vcode) |
|---|
| 240 | body' <- transformExp recloseExp (subBody vcode) |
|---|
| 241 | started' <- newTVar False |
|---|
| 242 | traits' <- recloseTraitBlocks (subTraitBlocks vcode) |
|---|
| 243 | return $ vcode |
|---|
| 244 | { subOuterPads = outers' |
|---|
| 245 | , subInnerPad = inner' |
|---|
| 246 | , subBody = body' |
|---|
| 247 | , subStarted = Just started' |
|---|
| 248 | , subTraitBlocks = traits' |
|---|
| 249 | } |
|---|
| 250 | recloseCode vcode = return vcode |
|---|
| 251 | |
|---|
| 252 | recloseRef :: VRef -> STM VRef |
|---|
| 253 | recloseRef (MkRef (ICode cv)) |
|---|
| 254 | | Just (vcode :: VCode) <- fromTypeable cv = do |
|---|
| 255 | vcode' <- recloseCode vcode |
|---|
| 256 | return . MkRef . ICode $ vcode' |
|---|
| 257 | recloseRef ref = return ref |
|---|
| 258 | |
|---|
| 259 | reclosePad :: Pad -> STM Pad |
|---|
| 260 | reclosePad pad = fmap listToPad . forM (padToList pad) $ \(name, entry) -> do |
|---|
| 261 | entry' <- case v_twigil name of |
|---|
| 262 | TMagical -> return entry -- XXX - Prevent &?ROUTINE recursion |
|---|
| 263 | _ -> do |
|---|
| 264 | case entry of |
|---|
| 265 | PEStatic{ pe_proto = proto, pe_store = store } -> do |
|---|
| 266 | proto' <- recloseRef proto |
|---|
| 267 | ref <- readTVar store |
|---|
| 268 | ref' <- recloseRef ref |
|---|
| 269 | writeTVar store ref' |
|---|
| 270 | return entry{ pe_proto = proto' } |
|---|
| 271 | PELexical{ pe_proto = proto, pe_store = store } -> do |
|---|
| 272 | proto' <- recloseRef proto |
|---|
| 273 | ref <- readTVar store |
|---|
| 274 | ref' <- recloseRef ref |
|---|
| 275 | writeTVar store ref' |
|---|
| 276 | return entry{ pe_proto = proto' } |
|---|
| 277 | PEConstant{ pe_proto = proto } -> do |
|---|
| 278 | proto' <- recloseRef proto |
|---|
| 279 | return entry{ pe_proto = proto' } |
|---|
| 280 | return (name, entry') |
|---|
| 281 | |
|---|
| 282 | data ApplyKind = AKInline | AKDisplaced deriving (Show) |
|---|
| 283 | |
|---|
| 284 | enterSub :: ApplyKind -> VCode -> Eval Val -> Eval Val |
|---|
| 285 | enterSub appKind sub action = do |
|---|
| 286 | env <- ask |
|---|
| 287 | pad <- case subStarted sub of |
|---|
| 288 | Just tvar -> do |
|---|
| 289 | started <- stm $ readTVar tvar |
|---|
| 290 | if started |
|---|
| 291 | then refreshPad (subInnerPad sub) |
|---|
| 292 | -- `finallyM` warn "======= REFRESHED ==========" (subInnerPad sub, sub) |
|---|
| 293 | else (stm $ do |
|---|
| 294 | writeTVar tvar True |
|---|
| 295 | reclosePad (subInnerPad sub)) |
|---|
| 296 | -- `finallyM` warn "======= RECLOSED ==========" (tvar, subInnerPad sub) |
|---|
| 297 | _ -> do |
|---|
| 298 | -- warn "==== NOTHING ====" (subInnerPad sub) |
|---|
| 299 | return (subInnerPad sub) |
|---|
| 300 | rv <- case typ of |
|---|
| 301 | -- For coroutines, we secretly store a continuation into subCont |
|---|
| 302 | -- whenever "yield" occurs in it. However, the inner CC must be |
|---|
| 303 | -- delimited on the subroutine boundary, otherwise the resuming |
|---|
| 304 | -- continuation will continue into the rest of the program, |
|---|
| 305 | -- which is now how coroutines are supposed to work. |
|---|
| 306 | -- On the other hand, the normal &?CALLER_CONTINUATION must still |
|---|
| 307 | -- work as an undelimiated continuation, which is why callCC here |
|---|
| 308 | -- occurs before resetT. |
|---|
| 309 | SubCoroutine -> tryT . callCC $ \cc -> resetT $ do |
|---|
| 310 | doFix <- fixEnv cc env pad |
|---|
| 311 | local doFix runAction |
|---|
| 312 | |
|---|
| 313 | -- _ | typ >= SubBlock -> tryT $ do |
|---|
| 314 | _ -> tryT $ do |
|---|
| 315 | doFix <- fixEnv return env pad |
|---|
| 316 | local doFix runAction |
|---|
| 317 | {- |
|---|
| 318 | _ -> tryT . callCC $ \cc -> do |
|---|
| 319 | doFix <- fixEnv cc env pad |
|---|
| 320 | local doFix runAction |
|---|
| 321 | -} |
|---|
| 322 | |
|---|
| 323 | -- warn "XXX" () |
|---|
| 324 | doFix <- fixEnv return env pad |
|---|
| 325 | local doFix $ do |
|---|
| 326 | runBlocks (filter (rejectKeepUndo rv . subName) . subLeaveBlocks) |
|---|
| 327 | when (rv == VControl (ControlLoop LoopLast)) $ |
|---|
| 328 | -- We won't have a chance to run the LAST block |
|---|
| 329 | -- once we exit outside the lexical block, so do it now |
|---|
| 330 | runBlocks subLastBlocks |
|---|
| 331 | assertBlocks subPostBlocks "POST" |
|---|
| 332 | case rv of |
|---|
| 333 | VControl l@(ControlLeave ftyp depth val) -> do |
|---|
| 334 | let depth' = if ftyp typ then depth - 1 else depth |
|---|
| 335 | if depth' < 0 |
|---|
| 336 | then return val |
|---|
| 337 | else retControl l{ leaveDepth = depth' } |
|---|
| 338 | VControl ControlExit{} -> retShift rv |
|---|
| 339 | VError{} -> retShift rv -- XXX - Implement CATCH block here |
|---|
| 340 | _ -> return rv |
|---|
| 341 | where |
|---|
| 342 | rejectKeepUndo VUndef = (/= __"KEEP") |
|---|
| 343 | rejectKeepUndo (VControl (ControlLeave _ _ val)) = \n -> rejectKeepUndo val n && (n /= __"NEXT") |
|---|
| 344 | rejectKeepUndo (VControl (ControlLoop LoopNext)) = (/= __"KEEP") |
|---|
| 345 | rejectKeepUndo VControl{} = \n -> (n /= __"KEEP") && (n /= __"NEXT") |
|---|
| 346 | rejectKeepUndo VError{} = \n -> (n /= __"KEEP") && (n /= __"NEXT") |
|---|
| 347 | rejectKeepUndo _ = (/= __"UNDO") |
|---|
| 348 | runAction = do |
|---|
| 349 | assertBlocks subPreBlocks "PRE" |
|---|
| 350 | runBlocks subEnterBlocks |
|---|
| 351 | action |
|---|
| 352 | runBlocks f = mapM_ (evalExp . Syn "block" . (:[]) . Syn "sub" . (:[]) . Val . castV) (f (subTraitBlocks sub)) |
|---|
| 353 | assertBlocks f name = forM_ (f (subTraitBlocks sub)) $ \cv -> do |
|---|
| 354 | rv <- fromVal =<< (evalExp . Syn "block" . (:[]) . Syn "sub" . (:[]) . Val . castV $ cv) |
|---|
| 355 | if rv then return () else die (name ++ " assertion failed") (subName sub) |
|---|
| 356 | runBlocks' f = mapM_ (evalExp . Syn "block'" . (:[]) . Syn "sub" . (:[]) . Val . castV) (f (subTraitBlocks sub)) |
|---|
| 357 | assertBlocks' f name = forM_ (f (subTraitBlocks sub)) $ \cv -> do |
|---|
| 358 | rv <- fromVal =<< (evalExp . Syn "block'" . (:[]) . Syn "sub" . (:[]) . Val . castV $ cv) |
|---|
| 359 | if rv then return () else die (name ++ " assertion failed") (subName sub) |
|---|
| 360 | typ = subType sub |
|---|
| 361 | doCC :: (Val -> Eval b) -> [Val] -> Eval b |
|---|
| 362 | doCC cc [] = cc undef |
|---|
| 363 | doCC cc [v] = cc =<< evalVal v |
|---|
| 364 | doCC _ _ = internalError "enterSub: doCC list length > 1" |
|---|
| 365 | orig :: VCode -> VCode |
|---|
| 366 | orig sub = sub { subBindings = [], subParams = (map fst (subBindings sub)) } |
|---|
| 367 | |
|---|
| 368 | fixEnv :: (Val -> Eval Val) -> Env -> Pad -> Eval (Env -> Env) |
|---|
| 369 | fixEnv _cc env pad |
|---|
| 370 | | SubPrim <- typ = do |
|---|
| 371 | return $ \e -> e |
|---|
| 372 | { envLexical = pad `mappend` envLexical env |
|---|
| 373 | , envLexPads = (PRuntime pad:envLexPads env) |
|---|
| 374 | } |
|---|
| 375 | | AKInline <- appKind = do |
|---|
| 376 | -- Entering an inline call. |
|---|
| 377 | return $ \e -> e |
|---|
| 378 | { envLexical = pad `mappend` envLexical env |
|---|
| 379 | , envPackage = subPackage sub |
|---|
| 380 | , envLexPads = (PRuntime pad:envLexPads env) |
|---|
| 381 | } |
|---|
| 382 | | otherwise = do |
|---|
| 383 | -- callerRec <- genSym (cast "&?CALLER_CONTINUATION") (codeRef $ ccSub cc env) |
|---|
| 384 | pad' <- fmap (pad `mappend`) $ mergeLexPads (subOuterPads sub) |
|---|
| 385 | return $ \e -> e |
|---|
| 386 | { envLexical = pad' -- combine ([callerRec]) pad' |
|---|
| 387 | , envPackage = subPackage sub |
|---|
| 388 | , envLexPads = (PRuntime pad':subOuterPads sub) |
|---|
| 389 | } |
|---|
| 390 | ccSub :: (Val -> Eval Val) -> Env -> VCode |
|---|
| 391 | ccSub cc env = mkPrim |
|---|
| 392 | { subName = __"CALLER_CONTINUATION" |
|---|
| 393 | , subParams = makeParams env |
|---|
| 394 | , subBody = Prim $ doCC cc |
|---|
| 395 | } |
|---|
| 396 | |
|---|
| 397 | makeParams :: Env -> [Param] |
|---|
| 398 | makeParams MkEnv{ envContext = cxt, envLValue = lv } |
|---|
| 399 | = [ MkOldParam |
|---|
| 400 | { isInvocant = False |
|---|
| 401 | , isOptional = True |
|---|
| 402 | , isNamed = False |
|---|
| 403 | , isLValue = lv |
|---|
| 404 | , isWritable = lv |
|---|
| 405 | , isLazy = False |
|---|
| 406 | , paramName = cast $ case cxt of |
|---|
| 407 | CxtSlurpy _ -> "@?0" |
|---|
| 408 | _ -> "$?0" |
|---|
| 409 | , paramContext = cxt |
|---|
| 410 | , paramDefault = Val VUndef |
|---|
| 411 | } ] |
|---|
| 412 | |
|---|
| 413 | evalVal :: Val -> Eval Val |
|---|
| 414 | evalVal val@VV{} = do |
|---|
| 415 | env <- ask |
|---|
| 416 | let cxt = envContext env |
|---|
| 417 | lv = envLValue env |
|---|
| 418 | if lv || cxt == CxtVoid then return val else val ./ cxt |
|---|
| 419 | evalVal val@(VRef ref) = do |
|---|
| 420 | lv <- asks envLValue |
|---|
| 421 | if lv |
|---|
| 422 | then return val |
|---|
| 423 | else if refType ref == mkType "Scalar::Const" |
|---|
| 424 | then evalVal =<< readRef ref |
|---|
| 425 | else do |
|---|
| 426 | typ <- evalValType val |
|---|
| 427 | if isaType "Junction" typ |
|---|
| 428 | then evalVal =<< readRef ref |
|---|
| 429 | else return val |
|---|
| 430 | evalVal val = return val |
|---|