Changeset 14015
- Timestamp:
- 10/07/06 15:25:28 (2 years ago)
- Files:
-
- 1 modified
-
src/Pugs/Monads.hs (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/Pugs/Monads.hs
r12924 r14015 16 16 enterLValue, enterRValue, 17 17 enterLex, enterContext, enterEvalContext, enterPackage, enterCaller, 18 enterGiven, enterWhen, enter While, genSymPrim, genSymCC,18 enterGiven, enterWhen, enterLoop, genSymPrim, genSymCC, 19 19 enterBlock, enterSub, envEnterCaller, 20 20 evalVal, tempVar, … … 25 25 import Pugs.AST 26 26 import Pugs.Types 27 import Control.Monad.RWS 27 import Control.Monad.RWS (MonadPlus(..)) 28 28 import qualified Data.Map as Map 29 29 … … 106 106 { envLexical = MkPad (lex `Map.intersection` envImplicit env) 107 107 } 108 , envDepth = envDepth env + 1108 , envDepth = (FrameRoutine:envDepth env) 109 109 , envImplicit = Map.fromList [(cast "$_", ())] 110 110 } … … 118 118 Used by "Pugs.Eval"'s implementation of 'Pugs.Eval.reduce' for @\"given\"@. 119 119 -} 120 enterGiven :: VRef -- ^ Reference to the value to topicalise 121 -> Eval a -- ^ Action to perform within the new scope 120 enterGiven :: Eval a -- ^ Action to perform within the new scope 122 121 -> Eval a 123 enterGiven topic action = do 124 sym <- genSym (cast "$_") topic 125 enterLex [sym] action 126 127 {-| 128 Bind @&continue@ and @&break@ to subs that break out of the @when@ body 129 and topicalising block respectively, then perform the given evaluation 130 in the new lexical scope. 131 122 enterGiven = local (\e -> e{ envDepth = (FrameGiven:envDepth e) }) 123 124 {-| 132 125 Note that this function is /not/ responsible for performing the actual @when@ 133 126 test, nor is it responsible for adding the implicit @break@ to the end of the … … 135 128 (see the entry for @('Syn' \"when\" ... )@). 136 129 -} 137 enterWhen :: Exp -- ^ The expression that @&break@ should be bound to 138 -> Eval Val -- ^ The @when@'s body block, as an evaluation 130 enterWhen :: Eval Val -- ^ The @when@'s body block, as an evaluation 139 131 -> Eval Val 140 enterWhen break action = callCC $ \esc -> do 141 env <- ask 142 contRec <- genSubs env "&continue" $ continueSub esc 143 breakRec <- genSubs env "&break" $ breakSub 144 enterLex (contRec ++ breakRec) action 145 where 146 continueSub esc env = mkPrim 147 { subName = __"continue" 148 , subParams = makeParams env 149 , subBody = Prim ((esc =<<) . headVal) 150 } 151 breakSub env = mkPrim 152 { subName = __"break" 153 , subParams = makeParams env 154 , subBody = break 155 } 156 157 {-| 158 Bind @&last@ and @&next@ to subs that respectively break-out-of and repeat the 159 @while@\/@until@, then perform the given evaluation in the new lexical scope. 160 161 Note that this function is /not/ responsible for performing the actual 162 @while@\/@until@ test; it is the responsibility of the caller to add such a 163 test to the top of the body evaluation. 164 -} 165 enterWhile :: Eval Val -- ^ Evaluation representing loop test & body 166 -> Eval Val 167 enterWhile action = genSymCC "&last" $ \symLast -> do 168 -- genSymPrim "&next" (const action) $ \symNext -> do 169 callCC $ \esc -> genSymPrim "&next" (const $ action >>= esc) $ \symNext -> do 170 enterLex [symLast, symNext] action 132 enterWhen action = do 133 rv <- action 134 case rv of 135 VControl (ControlGiven GivenContinue) -> retEmpty 136 VControl (ControlGiven GivenBreak) -> retShiftEmpty 137 _ -> retShift rv 138 139 {-| 140 Register the fact that we are inside a loop block. 141 -} 142 enterLoop :: Eval Val -- ^ Evaluation representing loop test & body 143 -> Eval Val 144 enterLoop = local (\e -> e{ envDepth = (FrameLoop:envDepth e) }) 171 145 172 146 {-| … … 216 190 217 191 {-| 218 Create a Perl 6 @&?BLOCK_EXIT@ function that, when activated, breaks out of219 the block scope by activating the current continuation. The block body220 evaluation is then performed in a new lexical scope with @&?BLOCK_EXIT@221 installed.222 223 192 Used by 'Pugs.Eval.reduce' when evaluating @('Syn' \"block\" ... )@ 224 193 expressions. 225 194 -} 226 195 enterBlock :: Eval Val -> Eval Val 227 enterBlock action = callCC $ \esc -> do 228 env <- ask 229 exitRec <- genSubs env "&?BLOCK_EXIT" $ escSub esc 230 local (\e -> e{ envOuter = Just env }) $ enterLex exitRec action 231 where 232 escSub esc env = mkPrim 233 { subName = __"BLOCK_EXIT" 234 , subParams = makeParams env 235 , subBody = Prim ((esc =<<) . headVal) 236 } 196 enterBlock action = local (\e -> e{ envOuter = Just e }) action 237 197 238 198 enterSub :: VCode -> Eval Val -> Eval Val 239 199 enterSub sub action 240 | typ >= SubPrim = action -- primitives just happen200 | typ >= SubPrim = runAction -- primitives just happen 241 201 | otherwise = do 242 202 env <- ask 243 if typ >= SubBlock244 then do203 rv <- if typ >= SubBlock 204 then resetT $ do 245 205 doFix <- fixEnv return env 246 local doFix action247 else resetT $callCC $ \cc -> do206 local doFix runAction 207 else resetT . callCC $ \cc -> do 248 208 doFix <- fixEnv cc env 249 local doFix action 209 local doFix runAction 210 runBlocks (filter (rejectKeepUndo rv . subName) . subLeaveBlocks) 211 212 when (rv == VControl (ControlLoop LoopLast)) $ 213 -- We won't have a chance to run the LAST block 214 -- once we exit outside the lexical block, so do it now 215 runBlocks subLastBlocks 216 217 assertBlocks subPostBlocks "POST" 218 case rv of 219 VControl l@(ControlLeave ftyp depth val) -> do 220 let depth' = if ftyp typ then depth - 1 else depth 221 if depth' < 0 222 then return val 223 else retControl l{ leaveDepth = depth' } 224 VControl ControlExit{} -> retShift rv 225 _ -> return rv 250 226 where 227 rejectKeepUndo VUndef = (/= __"KEEP") 228 rejectKeepUndo (VControl (ControlLeave _ _ val)) = \n -> rejectKeepUndo val n && (n /= __"NEXT") 229 rejectKeepUndo (VControl (ControlLoop LoopNext)) = (/= __"KEEP") 230 rejectKeepUndo VControl{} = \n -> (n /= __"KEEP") && (n /= __"NEXT") 231 rejectKeepUndo VError{} = \n -> (n /= __"KEEP") && (n /= __"NEXT") 232 rejectKeepUndo _ = (/= __"UNDO") 233 runAction = do 234 assertBlocks subPreBlocks "PRE" 235 runBlocks subEnterBlocks 236 action 237 runBlocks f = mapM_ (evalExp . Syn "block" . (:[]) . Syn "sub" . (:[]) . Val . castV) (f sub) 238 assertBlocks f name = forM_ (f sub) $ \cv -> do 239 rv <- fromVal =<< (evalExp . Syn "block" . (:[]) . Syn "sub" . (:[]) . Val . castV $ cv) 240 if rv then return () else retError (name ++ " assertion failed") (subName sub) 251 241 typ = subType sub 252 242 doCC :: (Val -> Eval b) -> [Val] -> Eval b … … 323 313 return val 324 314 325 headVal :: [Val] -> Eval Val326 headVal [] = retEmpty327 headVal (v:_) = return v328 329 315 tempVar :: Var -> Val -> Eval a -> Eval a 330 316 tempVar var val action = do
