Changeset 14113

Show
Ignore:
Timestamp:
10/09/06 17:26:24 (2 years ago)
Author:
audreyt
Message:

r14985@T: audreyt | 2006-10-09 16:45:12 +0800

  • Use MonadError? instead of MonadCont? for error handling. This will help separate out continuations with exceptions.
Location:
src/Pugs
Files:
11 modified

Legend:

Unmodified
Added
Removed
  • src/Pugs/AST/Eval.hs

    r13592 r14113  
    1010 
    1111{- Eval Monad -} 
    12 type Eval = EvalT (ContT Val (ReaderT Env SIO)) 
     12type Eval = EvalT (ErrorT Val (ReaderT Env SIO)) 
    1313newtype EvalT m a = EvalT { runEvalT :: m a } 
    1414 
    1515instance ((:>:) (Eval a)) (SIO a) where cast = liftSIO 
    1616 
     17liftEither :: Either a a -> a 
     18liftEither (Left a) = a 
     19liftEither (Right a) = a 
     20 
    1721runEvalSTM :: Env -> Eval Val -> STM Val 
    18 runEvalSTM env = runSTM . (`runReaderT` enterAtomicEnv env) . (`runContT` return) . runEvalT 
     22runEvalSTM env = fmap liftEither . runSTM . (`runReaderT` enterAtomicEnv env) . runErrorT . runEvalT 
    1923 
    2024runEvalIO :: Env -> Eval Val -> IO Val 
    21 runEvalIO env = runIO . (`runReaderT` env) . (`runContT` return) . runEvalT 
     25runEvalIO env = fmap liftEither . runIO . (`runReaderT` env) . runErrorT . runEvalT 
    2226 
    2327tryIO :: a -> IO a -> Eval a 
     
    4145       --     @esc@ is the current (sub)continuation 
    4246       -> Eval a 
    43 shiftT e = EvalT . ContT $ \k -> 
    44     runContT (runEvalT . e $ lift . lift . k) return 
     47shiftT f = do 
     48    rv <- f (error "invalid use of shiftT under ErrorT") 
     49    EvalT (throwError rv) 
    4550 
    4651{-| 
     
    8792resetT :: Eval Val -- ^ An evaluation, possibly containing a 'shiftT' 
    8893       -> Eval Val 
    89 resetT e = lift . lift $ 
    90     runContT (runEvalT e) return 
     94resetT e = catchError e return 
    9195 
    9296instance Monad Eval where 
     
    97101    fail str = do 
    98102        pos <- asks envPos' 
    99         shiftT . const . return $ errStrPos (cast str) pos 
     103        EvalT (throwError $ errStrPos (cast str) pos) 
     104 
     105instance Error Val where 
     106    noMsg = errStr "" 
     107    strMsg = errStr 
    100108 
    101109instance MonadTrans EvalT where 
     
    111119    throwError err = do 
    112120        pos <- asks envPos' 
    113         shiftT . const . return $ errValPos err pos 
    114     catchError _ _ = fail "catchError unimplemented" 
     121        EvalT (throwError $ errValPos err pos) 
     122    catchError (EvalT action) handler = EvalT (catchError action (runEvalT . handler)) 
    115123 
    116124{-| 
     
    161169    local f m = EvalT $ local f (runEvalT m) 
    162170 
     171{- 
    163172instance MonadCont Eval where 
    164173    -- callCC :: ((a -> Eval b) -> Eval a) -> Eval a 
    165174    callCC f = EvalT . callCCT $ \c -> runEvalT . f $ \a -> EvalT $ c a 
     175-} 
    166176 
    167177{- 
  • src/Pugs/AST/Internals.hs

    r14039 r14113  
    1010    InitDat(..), 
    1111 
    12     EvalT(..), ContT(..), SubAssoc(..), 
     12    EvalT(..), SubAssoc(..), 
    1313 
    1414    Pad(..), PadEntry(..), PadMutator, -- uses Var, TVar, VRef 
     
    5353    transformExp, 
    5454 
    55     runEvalSTM, runEvalIO, shiftT, resetT, callCC, 
     55    runEvalSTM, runEvalIO, shiftT, resetT, catchT, 
    5656    undef, defined, tryIO, guardSTM, guardIO, guardIOexcept, 
    5757    readRef, writeRef, clearRef, dumpRef, forceRef, 
     
    7676    newObjectId, runInvokePerl5, 
    7777     
    78     errStrPos, errValPos, enterAtomicEnv, valToBool, envPos', -- for circularity 
     78    errStr, errStrPos, errValPos, enterAtomicEnv, valToBool, envPos', -- for circularity 
    7979    expToEvalVal, -- Hack, should be removed once it's figured out how 
    8080 
     
    8585import Pugs.Internals 
    8686import Pugs.Types 
    87 import Pugs.Cont hiding (shiftT, resetT) 
    8887import qualified Data.Set       as Set 
    8988import qualified Data.Map       as Map 
     
    131130#include "../Types/Pair.hs" 
    132131#include "../Types/Object.hs" 
     132 
     133catchT :: ((Val -> Eval b) -> Eval Val) -> Eval Val 
     134catchT action = resetT (action retShift) 
    133135 
    134136{-| 
     
    712714    deriving (Show, Eq, Ord, Typeable) {-!derive: YAML_Pos!-} 
    713715 
     716errStr :: VStr -> Val 
     717errStr str = VError (VStr str) [] 
     718 
    714719errStrPos :: VStr -> Pos -> Val 
    715720errStrPos str pos = VError (VStr str) [pos] 
     
    14861491 
    14871492retShift :: Val -> Eval a 
    1488 retShift = shiftT . const . return 
     1493-- retShift = shiftT . const . return 
     1494retShift = EvalT . throwError 
    14891495 
    14901496retShiftEmpty :: Eval a 
    1491 retShiftEmpty = shiftT (const retEmpty) 
     1497-- retShiftEmpty = shiftT (const retEmpty) 
     1498retShiftEmpty = retShift =<< retEmpty 
    14921499 
    14931500defined :: VScalar -> Bool 
     
    18471854    typeOf (MkRef x) = typeOf x 
    18481855 
    1849 instance Typeable1 (EvalT (ContT Val (ReaderT Env SIO))) where 
     1856instance Typeable1 (EvalT (ErrorT Val (ReaderT Env SIO))) where 
    18501857    typeOf1 _ = typeOf () 
    18511858 
  • src/Pugs/AST/Internals.hs-boot

    r12460 r14113  
    2424 
    2525envPos' :: Env -> Pos 
     26errStr :: VStr -> Val 
    2627errStrPos :: VStr -> Pos -> Val 
    2728errValPos :: Val -> Pos -> Val 
  • src/Pugs/Eval.hs

    r14079 r14113  
    187187evalRef ref = do 
    188188    if refType ref == (mkType "Thunk") then forceRef ref else do 
    189     val <- callCC $ \esc -> do 
     189    val <- catchT $ \esc -> do 
    190190        MkEnv{ envContext = cxt, envLValue = lv, envClasses = cls } <- ask 
    191191        let typ = typeOfCxt cxt 
  • src/Pugs/Eval/Var.hs

    r13861 r14113  
    103103doFindVarRef :: Var -> Eval (Maybe (TVar VRef)) 
    104104doFindVarRef var = do 
    105     callCC $ \foundIt -> do 
    106         lexSym  <- fmap (findSym var . envLexical) ask 
    107         when (isJust lexSym) $ foundIt lexSym 
    108         -- XXX - this is bogus; we should not fallback if it's not in lex csope. 
    109         glob    <- liftSTM . readTVar . envGlobal =<< ask 
    110         var'    <- toQualified var 
    111         let globSym = findSym var' glob 
    112         when (isJust globSym) $ foundIt globSym 
    113         -- XXX - ditto for globals 
    114         let globSym = findSym (toGlobalVar var) glob 
    115         when (isJust globSym) $ foundIt globSym 
    116         return Nothing 
     105    lexSym  <- fmap (findSym var . envLexical) ask 
     106    if isJust lexSym then return lexSym else do 
     107    -- XXX - this is bogus; we should not fallback if it's not in lex csope. 
     108    glob    <- liftSTM . readTVar . envGlobal =<< ask 
     109    var'    <- toQualified var 
     110    let globSym = findSym var' glob 
     111    if isJust globSym then return globSym else do 
     112    -- XXX - ditto for globals 
     113    let globSym = findSym (toGlobalVar var) glob 
     114    if isJust globSym then return globSym else do 
     115    return Nothing 
    117116 
    118117 
  • src/Pugs/Internals.hs

    r14089 r14113  
    122122import Control.Monad.RWS (MonadIO(..), MonadReader(..), MonadState(..), MonadWriter(..), MonadTrans(..), asks, ReaderT(..), WriterT(..), when, join, liftM, filterM, modify, unless, gets, foldM, guard, liftM2, liftM3, fix, mplus, mappend, mzero, mconcat, msum, censor) 
    123123import Control.Monad.Identity (Identity(..)) 
    124 import Control.Monad.Error (MonadError(..)) 
     124import Control.Monad.Error (MonadError(..), ErrorT(..), Error(..)) 
    125125import Control.Concurrent 
    126126import Control.Concurrent.STM 
     
    153153 
    154154import qualified UTF8 
    155 import qualified Judy.CollectionsM as C 
     155import qualified Judy.CollectionsM as C () 
    156156import qualified Data.HashTable as H 
    157157import qualified Foreign as Foreign 
  • src/Pugs/Monads.hs

    r14060 r14113  
    186186         -> Eval Val -- ^ Result of passing the pad-transformer to the  
    187187                     --     \'action\' 
    188 genSymCC symName action = callCC $ \esc -> do 
     188genSymCC symName action = catchT $ \esc -> do 
    189189    genSymPrim symName (const $ esc undef) action 
    190190 
     
    205205                doFix <- fixEnv return env 
    206206                local doFix runAction 
    207             else resetT . callCC $ \cc -> do 
     207            else resetT . catchT $ \cc -> do 
    208208                doFix <- fixEnv cc env 
    209209                local doFix runAction 
  • src/Pugs/Parser.hs

    r14107 r14113  
    783783        imp <- option emptyExp ruleExpression 
    784784        let sub = _Var $ ('&':pkg) ++ if use then "::import" else "::unimport" 
    785         unsafeEvalExp $ Syn "if" 
     785 
     786        Val res <- unsafeEvalExp $ Syn "if" 
    786787            [ sub 
    787788            , App sub (Just $ Val $ VStr $ pkg) [imp] 
     
    789790            ] 
    790791 
    791         Val (VList exportList) <- unsafeEvalExp $ case lang of 
     792        Val (VList exportList) <- res `seq` unsafeEvalExp $ case lang of 
    792793            -- map { ~$_, [::Pkg.can($_)] }, @importlist 
    793794            "perl5" -> App (_Var "&map") Nothing [Syn "sub" 
     
    10571058vcode2initBlock :: Val -> RuleParser Exp 
    10581059vcode2initBlock code = do 
    1059     body <- vcode2startBlock code 
     1060    body    <- vcode2startBlock code 
    10601061    fstcode <- unsafeEvalExp $ Syn "sub" [ Val $ VCode mkSub { subBody = body } ] 
    1061     unsafeEvalExp $ 
     1062    Val res <- unsafeEvalExp $ 
    10621063        App (_Var "&push") (Just $ _Var "@*INIT") [ fstcode ] 
    1063     return $ App fstcode Nothing [] 
     1064    return (res `seq` App fstcode Nothing []) 
    10641065 
    10651066vcode2checkBlock :: Val -> RuleParser Exp 
    10661067vcode2checkBlock code = do 
    1067     body <- vcode2startBlock code 
     1068    body    <- vcode2startBlock code 
    10681069    fstcode <- unsafeEvalExp $  
    10691070        Syn "sub" [ Val $ VCode mkSub { subBody = checkForIOLeak body } ] 
    1070     unsafeEvalExp $ 
     1071    Val res <- unsafeEvalExp $ 
    10711072        App (_Var "&unshift") (Just $ _Var "@*CHECK") [ fstcode ] 
    1072     return $ App fstcode Nothing [] 
     1073    return (res `seq` App fstcode Nothing []) 
    10731074 
    10741075-- Constructs ------------------------------------------------ 
  • src/Pugs/Parser/Unsafe.hs

    r13802 r14113  
    4747            evl exp 
    4848    case val of 
    49         VError _ _ -> error $ pretty (val :: Val) 
    50         _           -> return $ Val val 
     49        VError{} -> error $ pretty (val :: Val) 
     50        _        -> return $ Val val 
    5151 
    5252{-# NOINLINE possiblyApplyMacro #-} 
  • src/Pugs/Prim/List.hs

    r13976 r14113  
    200200                    then fail 
    201201                        "When reducing using a chain-associative sub,\nthe sub must take exactly two arguments." 
    202                     else callCC $ \esc -> do 
     202                    else catchT $ \esc -> do 
    203203                        let doFold' x y = do 
    204204                            val <- doFold [x, y] 
  • src/Pugs/Run.hs

    r14018 r14113  
    273273        runEnv env{ envBody = ast, envDebug = Nothing } 
    274274        --     Right Nothing -> fail "" 
     275{-# OPTIONS_GHC -fglasgow-exts #-} 
     276 
     277{- 
     278 
     279  This needs to be redone as a proper Haskell parser, 
     280  which will be one of my next projects. But so far, 
     281  this works. 
     282 
     283  The operators are simple prefix operators 
     284  with zero or one argument, except for everything 
     285  that ultimatively goes into @ARGS for the Pugs 
     286  script. 
     287 
     288  If you change anything here, make sure all tests under 
     289  t/pugsrun/ still pass. Otherwise you might break building 
     290  for everybody, once you commit. 
     291 
     292-} 
     293 
     294-- | Command line argument parser for pugs. 
     295module Pugs.Run.Args ( 
     296    canonicalArgs, 
     297    gatherArgs, 
     298    unpackOptions, 
     299) where 
     300import Pugs.Internals 
     301 
     302{- |  
     303  Convert command line arguments into canonical form for  
     304  'Pugs.Run.runWithArgs'.  The switch ordering is defined 
     305  by compareArgs and is currently: 
     306 
     307  > (-h -v -V) (-I) (-d) (-w) (-c) (-C) (--external) (-M) (-n -p) (-0 -e other) 
     308 
     309  Args -M, -n and -p are converted to -e scripts by desugarDashE. 
     310-} 
     311canonicalArgs :: [String] -> [String] 
     312canonicalArgs x = concatMap procArg 
     313                . concatDashE 
     314                . desugarDashE 
     315                . sortBy compareArgs 
     316                . gatherArgs 
     317                . unpackOptions 
     318                $ x 
     319 
     320concatDashE :: [Arg] -> [Arg] 
     321concatDashE (Opt "-e" e:xs) = (Opt "-e" $ concat (intersperse "\n" (e:map optArg es))) : rest 
     322    where 
     323    (es, rest)          = partition isOptE xs 
     324    isOptE (Opt "-e" _) = True 
     325    isOptE _            = False 
     326concatDashE (x:xs) = (x:concatDashE xs) 
     327concatDashE xs = xs 
     328 
     329data Arg 
     330    = File !String 
     331    | Switch !Char 
     332    | Opt { _optFlag :: !String, optArg :: !String } 
     333    deriving Show 
     334 
     335procArg :: Arg -> [String] 
     336procArg (Opt name arg)  = [name, arg] 
     337procArg (File name)     = [name] 
     338procArg (Switch name)   = ['-':name:[]] 
     339 
     340unpackOptions :: [String] -> [String] 
     341unpackOptions []                = [] 
     342unpackOptions (("-"):rest)      = ("-":unpackOptions rest) 
     343unpackOptions opts@("--":_)     = opts 
     344unpackOptions (('-':opt):arg:rest) 
     345    | takesArg opt              = unpackOption opt ++ (arg:unpackOptions rest) 
     346unpackOptions (('-':opt):rest)  = unpackOption opt ++ unpackOptions rest 
     347unpackOptions opts@[_]          = opts 
     348unpackOptions (filename:rest)   = filename : "--" : rest 
     349 
     350takesArg :: String -> Bool 
     351takesArg xs     | xs `elem` withParam   = True 
     352takesArg (x:xs) | x `elem` composable   = takesArg xs 
     353takesArg _                              = False 
     354 
     355unpackOption :: String -> [String] 
     356unpackOption "" = [] -- base case for composing 
     357unpackOption opt 
     358    | Just short <- lookup ('-':opt) longOptions = [short] 
     359    | head opt `elem` composable = ['-', head opt] : unpackOption (tail opt) 
     360    | Just (prefix, param) <- prefixOpt opt = ['-':prefix, param] 
     361    | otherwise = ['-':opt] 
     362 
     363-- | List of options with long and sort variants, as tupples of long, short (with the dashes). 
     364longOptions :: [(String, String)] 
     365longOptions = [("--help", "-h"), ("--version", "-v")] 
     366 
     367-- | List of options that can have their argument just after, with no space. 
     368composable :: [Char] 
     369composable = "cdlnpw" 
     370 
     371-- | List of options that can take arguments 
     372withParam :: [String] 
     373withParam = words "e C B I M V:" 
     374 
     375prefixOpt :: [Char] -> Maybe (String, String) 
     376prefixOpt opt = msum $ map (findArg opt) withParam 
     377 
     378findArg :: Eq a => [a] -> [a] -> Maybe ([a], [a]) 
     379findArg arg prefix = do 
     380    param <- afterPrefix prefix arg 
     381    guard (not (null param)) 
     382    return (prefix, param) 
     383 
     384{- 
     385  Enforce a canonical order of command line switches.  Currently this is: 
     386 
     387  > (-h -v -V) (-I) (-d) (-w) (-c) (-C) (--external) (-M) (-n -p) (-0 -e other) 
     388 
     389  This makes pattern matching more convenient 
     390 
     391  Backwards incompatible changes: 
     392 
     393   *  -p and -n autochomp. 
     394 
     395   *  -p uses say() instead of print() 
     396-} 
     397 
     398compareArgs :: Arg -> Arg -> Ordering 
     399compareArgs a b = compare (argRank a) (argRank b) 
     400 
     401argRank :: Arg -> Int 
     402argRank (Switch 'h')         = -1 
     403argRank (Switch 'v')         = -1 
     404argRank (Opt "-V:" _)        = -1 
     405argRank (Switch 'V')         = -1 
     406argRank (Opt "-I" _)         = 0 
     407argRank (Switch 'd')         = 1 
     408argRank (Switch 'w')         = 2 
     409argRank (Switch 'c')         = 3 
     410argRank (Opt "-C" _)         = 4 
     411argRank (Opt "-B" _)         = 4 
     412argRank (Opt "--external" _) = 5 
     413argRank (Opt "-M" _)         = 98 
     414argRank (Switch 'n')         = 99   -- translated into Perl code (later) 
     415argRank (Switch 'p')         = 99   -- translated into Perl code (later) 
     416argRank (Switch 'l')         = 100  -- translated into Perl code (later) 
     417argRank (Switch '0')         = 100  -- translated into Perl code (later) 
     418argRank (Opt "-e" _)         = 100  -- translated into Perl code 
     419argRank _                    = 100  -- filename or @ARGS or whatever 
     420 
     421gatherArgs :: [String] -> [Arg] 
     422gatherArgs [] = [] 
     423gatherArgs ("-e":frag:rest)        = [Opt "-e" frag] ++ gatherArgs(rest) 
     424gatherArgs ("--external":mod:rest) = [Opt "--external" mod] ++ gatherArgs(rest) 
     425gatherArgs ("-I":dir:rest)         = [Opt "-I" dir] ++ gatherArgs(rest) 
     426gatherArgs ("-M":mod:rest)         = [Opt "-M" mod] ++ gatherArgs(rest) 
     427gatherArgs ("-C":backend:rest)     = [Opt "-C" backend] ++ gatherArgs(rest) 
     428gatherArgs ("-B":backend:rest)     = [Opt "-B" backend] ++ gatherArgs(rest) 
     429gatherArgs ("-V:":item:rest)       = [Opt "-V:" item] ++ gatherArgs(rest) 
     430gatherArgs (('-':[]):xs)           = [File "-"] ++ gatherArgs(xs) 
     431gatherArgs (("--"):rest)           = [File x | x <- rest] 
     432gatherArgs (('-':x:[]):xs)         = [Switch x] ++ gatherArgs(xs) 
     433gatherArgs (x:xs)                  = [File x] ++ gatherArgs(xs) 
     434 
     435{- collect "-e" switches together, 
     436   handle transformation of "-M", "-n" 
     437   and "-p" into "-e" fragments 
     438-} 
     439desugarDashE :: [Arg] -> [Arg] 
     440desugarDashE [] = [] 
     441desugarDashE ((Switch 'p'):args) = desugarDashE $ 
     442    (Opt "-e" "env $_; while (defined($_ = =<>)) { " : args) ++ [Opt "-e" "; say $_; }"] 
     443desugarDashE ((Switch 'n'):args) = desugarDashE $ 
     444    (Opt "-e" "env $_; while (defined($_ = =<>)) { " : args) ++ [Opt "-e" "}"] 
     445 
     446-- -E is like -e, but not accessible as a normal parameter and used only 
     447-- internally: 
     448--   "-e foo bar.pl" executes "foo" with @*ARGS[0] eq "bar.pl", 
     449--   "-E foo bar.pl" executes "foo" and then bar.pl. 
     450desugarDashE ((Opt "-M" mod):args) 
     451    | (mod', (_:args)) <- break (== '=') mod 
     452    = useWith $ mod' ++ " '" ++ escape args ++ "'.split(',')" 
     453    | otherwise 
     454    = useWith mod 
     455    where 
     456    useWith mod = desugarDashE ((Opt "-E" (";use " ++ mod ++ ";\n")):args) 
     457    escape [] = [] 
     458    escape ('\'':xs) = '\\':'\'':escape xs 
     459    escape ('\\':xs) = '\\':'\\':escape xs 
     460    escape (x:xs) = x:escape xs 
     461 
     462 
     463-- Preserve the curious Perl5 behaviour: 
     464--   perl -e 'print CGI->VERSION' -MCGI     # works 
     465--   perl print_cgi.pl -MCGI                # fails 
     466desugarDashE (x@(Opt "-e" _):y@(Opt "-E" _):args) = desugarDashE (y:x:args) 
     467desugarDashE ((Opt "-E" a):y@(Opt "-e" _):args) = desugarDashE ((Opt "-e" a):y:args) 
     468desugarDashE (x:xs) = (x:desugarDashE xs) 
    275469        --     x  -> fail $ "Error loading precompiled Prelude: " ++ show x