root/src/Pugs/Prim.hs

Revision 22989, 85.6 kB (checked in by audreyt, 8 months ago)

* GHC 6.10 support, part 2 of 3: Adjust for extensible exceptions.

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
Line 
1{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans -fno-full-laziness -fno-cse -fallow-overlapping-instances #-}
2
3{-|
4    Primitive operators.
5
6>   There hammer on the anvil smote,
7>   There chisel clove, and graver wrote;
8>   There forged was blade, and bound was hilt;
9>   The delver mined, the mason built...
10-}
11
12module Pugs.Prim (
13    primOp,
14    primDecl,
15    initSyms,
16    op2ChainedList,
17    op1Exit,
18
19    -- used by Pugs.Compile.Haskell
20    op0, op1, op2,
21
22    -- used Pugs.Eval
23    op1Return, op1Yield,
24    foldParam, op2Hyper, op1HyperPrefix, op1HyperPostfix, retSeq, atomicEval
25) where
26import Pugs.Internals
27import Pugs.Junc
28import Pugs.AST
29import Pugs.Types
30import Pugs.Monads
31import Pugs.Pretty
32import Text.Printf
33import Pugs.External
34import Pugs.Embed
35import Pugs.Eval.Var
36import Pugs.Meta ()
37import qualified Data.Map as Map
38import qualified Data.Set as Set
39import Data.IORef
40import System.IO.Error (isEOFError)
41
42import Pugs.Prim.Keyed
43import Pugs.Prim.Yaml
44import Pugs.Prim.Match
45import Pugs.Prim.List
46import Pugs.Prim.Numeric
47import Pugs.Prim.Lifts
48import Pugs.Prim.Eval
49import Pugs.Prim.Code
50import Pugs.Prim.Param
51import qualified Data.IntSet as IntSet
52import DrIFT.YAML
53import GHC.Exts (unsafeCoerce#)
54import GHC.Unicode
55import qualified Data.HashTable as H
56import Data.Time.LocalTime
57import Data.Time.Calendar.OrdinalDate
58import Data.Time.Calendar.MonthDay
59
60constMacro :: Exp -> [Val] -> Eval Val
61constMacro = const . expToEvalVal
62
63-- |Implementation of 0-ary and variadic primitive operators and functions
64-- (including list ops).
65op0 :: String -> [Val] -> Eval Val
66op0 "&"  = fmap opJuncAll . mapM fromVal
67op0 "^"  = fmap opJuncOne . mapM fromVal
68op0 "|"  = fmap opJuncAny . mapM fromVal
69op0 "want"  = const $ fmap VStr (asks (maybe "Item" envWant . envCaller))
70op0 "Bool::True"  = const . return $ VBool True
71op0 "Bool::False" = const . return $ VBool False
72op0 "True"  = constMacro . Val $ VBool True
73op0 "False" = constMacro . Val $ VBool False
74op0 "time"  = const $ do
75    clkt <- guardIO getCurrentTime
76    return $ VRat $ pugsTimeSpec clkt
77op0 "times"  = const $ do
78    ProcessTimes _ u s cu cs <- guardIO getProcessTimes
79    return . VList $ map (castV . (% (clocksPerSecond :: VInt)) . toInteger . fromEnum)
80        [u, s, cu, cs]
81op0 "Z" = op0Zip
82op0 "X" = op0Cross
83    -- op0 "minmax" = op0Minmax
84op0 "File::Spec::cwd" = const $ do
85    cwd <- guardIO getCurrentDirectory
86    return $ VStr cwd
87op0 "File::Spec::tmpdir" = const $ do
88    tmp <- guardIO getTemporaryDirectory
89    return $ VStr tmp
90op0 "Pugs::Internals::pi" = const $ return $ VNum pi
91op0 "self"    = const $ expToEvalVal (_Var "$__SELF__")
92op0 "say"     = const $ op1 "IO::say" (VHandle stdout)
93op0 "print"   = const $ op1 "IO::print" (VHandle stdout)
94op0 "return"  = const $ op1Return (retControl (ControlLeave (<= SubRoutine) 0 undef))
95op0 "yield"   = const $ op1Yield (retControl (ControlLeave (<= SubRoutine) 0 undef))
96op0 "leave"   = const $ retControl (ControlLeave (>= SubBlock) 0 undef)
97op0 "take"    = const $ assertFrame FrameGather retEmpty
98op0 "nothing" = const . return $ VBool True
99op0 "Pugs::Safe::safe_getc"     = const . op1Getc $ VHandle stdin
100op0 "Pugs::Safe::safe_readline" = const . op1Readline $ VHandle stdin
101op0 "reverse" = const $ return (VList [])
102op0 "chomp"   = const $ return (VList [])
103op0 "fork"    = const $ opPerl5 "fork" []
104op0 "defer"   = const $ do
105    env <- ask
106    if envAtomic env then guardSTM retry else fail "Cannot call &defer outside a contend block."
107op0 other = const $ fail ("Unimplemented listOp: " ++ other)
108
109-- |Implementation of unary primitive operators and functions
110op1 :: String -> Val -> Eval Val
111op1 "!"    = op1Cast (VBool . not)
112op1 "WHICH" = \x -> do
113    val <- fromVal x
114    return $ case val of
115        VObject o   -> castV . unObjectId $ objId o
116        _           -> val
117op1 "chop" = \x -> do
118    str <- fromVal x
119    return $ if null str
120        then VStr str
121        else VStr $ init str
122op1 "Scalar::chomp" = \x -> do
123    str <- fromVal x
124    return $ op1Chomp str
125op1 "Str::split" = op1Cast (castV . words)
126op1 "lc"         = op1Cast (VStr . map toLower)
127op1 "lcfirst"    = op1StrFirst toLower
128op1 "uc"         = op1Cast (VStr . map toUpper)
129op1 "ucfirst"    = op1StrFirst toUpper
130op1 "capitalize" = op1Cast $ VStr . (mapEachWord capitalizeWord)
131  where
132    mapEachWord _ [] = []
133    mapEachWord f str@(c:cs)
134        | isSpace c = c:(mapEachWord f cs)
135        | otherwise = f word ++ mapEachWord f rest
136          where (word,rest) = break isSpace str
137    capitalizeWord []     = []
138    capitalizeWord (c:cs) = toUpper c:(map toLower cs)
139op1 "quotemeta" = op1Cast (VStr . concat . map toQuoteMeta)
140op1 "undef" = const $ return undef
141op1 "undefine" = \x -> do
142    when (defined x) $ do
143        ref <- fromVal x
144        clearRef ref
145    return undef
146op1 "+"    = op1Numeric id
147op1 "abs"  = op1Numeric abs
148op1 "Pugs::Internals::truncate" = op1Round truncate
149op1 "Pugs::Internals::round"    = op1Round round
150op1 "Pugs::Internals::floor"    = op1Round floor
151op1 "Pugs::Internals::ceiling"  = op1Round ceiling
152op1 "cos"  = op1Floating cos
153op1 "sin"  = op1Floating sin
154op1 "tan"  = op1Floating tan
155op1 "sqrt" = op1Floating sqrt
156op1 "atan" = op1Floating atan
157op1 "post:i" = \x -> do
158    n <- fromVal x
159    return $ VComplex (0 :+ n)
160op1 "post:++" = \x -> atomicEval $ do
161    ref <- fromVal x
162    val <- fromVal x
163    val' <- case val of
164        (VStr str)  -> return (VStr $ strInc str)
165        _           -> op1Numeric (+1) val
166    writeRef ref val'
167    case val of
168        (VStr _)    -> return val
169        _           -> op1 "+" val
170op1 "++"   = \mv -> do
171    op1 "post:++" mv
172    fromVal mv
173op1 "post:--"   = \x -> atomicEval $ do
174    ref <- fromVal x
175    val <- fromVal x
176    writeRef ref =<< op1Numeric (\x -> x - 1) val
177    return val
178op1 "--"   = \mv -> do
179    op1 "post:--" mv
180    fromVal mv
181op1 "-"    = op1Numeric negate
182op1 "item" = \v -> return $ case v of
183    VList vs    -> VRef . arrayRef $ vs
184    _           -> v
185op1 "sort" = \v -> do
186    args    <- fromVal v
187    (valList, sortByGiven) <- case args of
188        (v:vs) -> do
189            ifValTypeIsa v "Code"
190                (return (vs, Just v))
191                (ifValTypeIsa (last args) "Code"
192                    (return (init args, Just $ last args))
193                    (return (args, Nothing)))
194        _  -> return (args, Nothing)
195    sortBy <- case sortByGiven of
196        Nothing -> readVar (cast "&*infix:cmp")
197        Just subVal -> return subVal
198    sub <- fromVal sortBy
199    sorted <- (`sortByM` valList) $ \v1 v2 -> do
200        rv  <- enterEvalContext (cxtItem "Int") $ App (Val sub) Nothing [Val v1, Val v2]
201        int <- fromVal rv
202        return (int <= (0 :: Int))
203    retSeq sorted
204op1 "Scalar::reverse" = \v -> do
205    str     <- fromVal v
206    return (VStr $ reverse str)
207op1 "List::reverse" = \v -> do
208    vlist <- fromVal v
209    return (VList $ reverse vlist)
210op1 "list" = op1Cast VList
211op1 "pair" = op1Cast $ VList . (map $ \(k, v) -> castV ((VStr k, v) :: VPair))
212op1 "~"    = op1Cast VStr
213op1 "?"    = op1Cast VBool
214op1 "int"  = op1Cast VInt
215op1 "+^"   = op1Cast (VInt . pred . negate) -- Arbitrary precision complement- 0 ==> -1 / 1 ==> -2
216op1 "~^"   = op1Cast (VStr . mapStr complement)
217op1 "?^"   = op1 "!"
218op1 "\\"   = return . doCapture
219    where
220    doCapture :: Val -> Val
221    doCapture v@(VRef (MkRef IScalar{})) = VRef . scalarRef $ v
222    doCapture v@VRef{}                   = v
223    doCapture (VList vs)                 = VRef . arrayRef $ vs
224    doCapture v                          = VRef . scalarRef $ v
225op1 "^" = op2RangeExclRight (VNum 0)
226op1 "post:..."  = op1Range
227op1 "not"  = op1 "!"
228op1 "true" = op1 "?"
229op1 "any"  = op1Cast opJuncAny
230op1 "all"  = op1Cast opJuncAll
231op1 "one"  = op1Cast opJuncOne
232op1 "none" = op1Cast opJuncNone
233op1 "perl" = op1Pretty $ MkPrettyPrinter pretty
234op1 "guts" = op1Pretty $ MkPrettyPrinter priggy
235op1 "yaml" = dumpYaml
236op1 "require_haskell" = \v -> do
237    name    <- fromVal v
238    externRequire "Haskell" name
239    return $ VBool True
240op1 "require_parrot" = \v -> do
241    -- name    <- fromVal v
242    fail "evalParrotFile has bitrotten." -- io $ evalParrotFile name
243    return $ VBool True
244op1 "require_perl5" = \v -> do
245    pkg     <- fromVal v
246    let requireLine = "require " ++ pkg ++ "; '" ++ pkg ++ "'"
247    val     <- evalPerl5WithCurrentEnv requireLine
248    evalExp (_Sym SOur (':':'*':pkg) mempty (Val val) (newMetaType pkg))
249    return val
250op1 "require_java" = \v -> do
251    pkg     <- fromVal v
252    let requireLine = "package main; use Inline (qw( Java STUDY AUTOSTUDY 1 STUDY ), ['" ++ mod ++ "']); '" ++ pkg ++ "'"
253        lastPart    = last (split "::" pkg)
254        mod         = concat (intersperse "." (split "::" pkg))
255    val     <- evalPerl5WithCurrentEnv requireLine
256    evalExp (_Sym SOur (':':'*':pkg) mempty (Val val) (newMetaType pkg))
257    when (lastPart /= pkg) $ do
258        evalExp_ (_Sym SOur (':':'*':lastPart) mempty (Val val) (newMetaType lastPart))
259    return val
260op1 "Pugs::Internals::eval_parrot" = \v -> do
261    -- code    <- fromVal v
262    fail "evalParrot has bitrotten."
263    {-
264    io . evalParrot $ case code of
265        ('.':_) -> code
266        _       -> unlines
267            [ ".sub pugs_eval_parrot"
268            -- , "trace 1"
269            , code
270            , ".end"
271            ]
272    -}
273    return $ VBool True
274
275-- XXX - revert these two to Prelude.pm's ::Disabled version once YAML+Closure is working
276op1 "use" = opRequire True
277op1 "require" = opRequire False
278
279op1 "Pugs::Internals::use" = opRequire True
280op1 "Pugs::Internals::require" = opRequire False
281op1 "Pugs::Internals::eval_perl6" = \v -> do
282    str <- fromVal v
283    opEval quiet "<eval>" (encodeUTF8 str)
284    where quiet = MkEvalStyle { evalResult = EvalResultLastValue
285                              , evalError  = EvalErrorUndef }
286op1 "evalfile" = \v -> do
287    filename <- fromVal v
288    opEvalFile filename
289op1 "Pugs::Internals::eval_perl5" = \v -> do
290    str     <- fromVal v
291    env     <- ask
292    lex     <- asks envLexical
293    let vars = [ v | v@MkVar{ v_sigil = SScalar, v_twigil = TNil } <- Set.toList (padKeys lex), v /= varTopic ]
294        code = "sub { " ++ codeSafe ++ codeVar ++ str ++ "\n}"
295        codeSafe | safeMode  = "use ops (':default', 'binmode', 'entereval');"
296                 | otherwise = ""
297        codeVar | null vars = ""
298                | otherwise = "my (" ++ (concat $ intersperse ", " (map cast vars)) ++ ") = @_;"
299    vals    <- mapM readVar vars
300    rv  <- tryIO (Perl5ErrorString "") $ do
301        envSV   <- mkEnv env
302        sub     <- evalPerl5 code envSV 0
303        args    <- mapM newSVval vals
304        invokePerl5 sub nullSV args envSV (enumCxt $ envContext env)
305    case rv of
306        Perl5ReturnValues [x]   -> io $ svToVal x
307        Perl5ReturnValues xs    -> io $ fmap VList (mapM svToVal xs)
308        Perl5ErrorString str    -> fail str
309        Perl5ErrorObject err    -> throwError (PerlSV err)
310op1 "Pugs::Internals::evalfile_p6y" = op1EvalFileP6Y
311op1 "Pugs::Internals::eval_p6y"     = op1EvalP6Y
312op1 "Pugs::Internals::eval_haskell" = op1EvalHaskell
313op1 "Pugs::Internals::eval_yaml" = evalYaml
314op1 "contend" = \v -> do
315    env <- ask
316    guardSTM . runEvalSTM env . evalExp $ App (Val v) Nothing []
317op1 "try" = \v -> do
318    sub <- fromVal v
319    env <- ask
320    val <- tryT $ case envAtomic env of
321        True    -> guardSTM . runEvalSTM env . evalExp $ App (Val $ VCode sub) Nothing []
322        False   -> guardIO . runEvalIO env . evalExp $ App (Val $ VCode sub) Nothing []
323    retEvalResult style val
324    where
325    style = MkEvalStyle
326        { evalResult = EvalResultLastValue
327        , evalError  = EvalErrorUndef
328        }
329-- Tentative implementation of nothingsmuch's lazy proposal.
330op1 "lazy" = \v -> do
331    sub     <- fromVal v
332    memo    <- io $ newTVarIO Nothing
333    let exp = App (Val $ VCode sub) Nothing []
334        thunk = do
335            cur <- stm $ readTVar memo
336            maybe eval return cur
337        eval = do
338            res <- evalExp exp
339            stm $ writeTVar memo (Just res)
340            return res
341    typ <- inferExpType exp
342    return . VRef . thunkRef $ MkThunk thunk typ
343
344op1 "defined" = op1Cast (VBool . defined)
345op1 "last" = const $ assertFrame FrameLoop $ op1ShiftOut (VControl (ControlLoop LoopLast))
346op1 "next" = const $ assertFrame FrameLoop $ op1ShiftOut (VControl (ControlLoop LoopNext))
347op1 "redo" = const $ assertFrame FrameLoop $ op1ShiftOut (VControl (ControlLoop LoopRedo))
348op1 "continue" = const $ assertFrame FrameWhen $ op1ShiftOut (VControl (ControlWhen WhenContinue))
349op1 "break" = const $ assertFrame FrameWhen $ op1ShiftOut (VControl (ControlWhen WhenBreak))
350op1 "return" = op1Return . op1ShiftOut . VControl . ControlLeave (<= SubRoutine) 0
351op1 "yield" = op1Yield . op1ShiftOut . VControl . ControlLeave (<= SubRoutine) 0
352op1 "leave" = op1ShiftOut . VControl . ControlLeave (>= SubBlock) 0
353op1 "take" = \v -> assertFrame FrameGather $ do
354    glob    <- askGlobal
355    arr     <- findSymRef (cast "$*TAKE") glob
356    push    <- doArray (VRef arr) array_push
357    push (listVal v)
358    retEmpty
359op1 "sign" = \v -> withDefined [v] $
360    op1Cast (VInt . signum) v
361
362op1 "srand" = \v -> do
363    x <- fromVal v
364    guardSTM . unsafeIOToSTM $ do
365       seed <- if defined v
366          then return x
367          else randomRIO (0, 2^(31::Int))
368       setStdGen $ mkStdGen seed
369    return (castV True)
370op1 "rand"  = \v -> do
371    x    <- fromVal v
372    rand <- guardSTM . unsafeIOToSTM
373               $ getStdRandom (randomR (0, if x == 0 then 1 else x))
374    return $ VNum rand
375op1 "say" = op2 "IO::say" (VHandle stdout)
376op1 "print" = op2 "IO::print" (VHandle stdout)
377op1 "IO::say" = \v -> op2 "IO::say" v $ VList []
378op1 "IO::print" = \v -> op2 "IO::print" v $ VList []
379op1 "IO::next" = \v -> do
380    fh  <- fromVal v
381    guardIO $ fmap (VStr . (++ "\n") . decodeUTF8) (hGetLine fh)
382op1 "Pugs::Safe::safe_print" = \v -> do
383    str  <- fromVal v
384    guardIO . putStr $ encodeUTF8 str
385    return $ VBool True
386op1 "die" = \v -> do
387    v'      <- fromVal $! v
388    poss    <- asks envPosStack
389    retShift $! VError (errmsg $! v') poss
390    where
391    errmsg VUndef      = VStr "Died"
392    errmsg VType{}     = VStr "Died"
393    errmsg (VStr "")   = VStr "Died"
394    errmsg (VList [])  = VStr "Died"
395    errmsg (VList [x]) = x
396    errmsg x           = x
397op1 "warn" = \v -> do
398    strs <- fromVal v
399    errh <- readVar $ cast "$*ERR"
400    poss    <- asks envPosStack
401    op2 "IO::say" errh $ VList [ VStr $ pretty (VError (errmsg strs) poss) ]
402    where
403    errmsg "" = VStr "Warning: something's wrong"
404    errmsg x  = VStr x
405op1 "fail" = op1 "fail_" -- XXX - to be replaced by Prelude later
406op1 "fail_" = \v -> do
407    throw <- fromVal =<< readVar (cast "$*FAIL_SHOULD_DIE")
408    if throw then op1 "die" (errmsg v) else do
409    poss    <- asks envPosStack
410    let die = retShift $ VError (errmsg v) poss
411        dieThunk = VRef . thunkRef $ MkThunk die (mkType "Failure")
412    op1Return (retControl (ControlLeave (<= SubRoutine) 0 dieThunk))
413    where
414    errmsg VUndef      = VStr "Failed"
415    errmsg VType{}     = VStr "Failed"
416    errmsg (VStr "")   = VStr "Failed"
417    errmsg (VList [])  = VStr "Failed"
418    errmsg (VList [x]) = x
419    errmsg x           = x
420op1 "exit" = op1Exit
421op1 "readlink" = \v -> do
422    str  <- fromVal v
423    guardIO $ fmap VStr (readSymbolicLink str)
424op1 "sleep" = \v -> do
425    x <- fromVal v :: Eval VNum
426    guardIO $ do
427        start   <- getCurrentTime
428        threadDelay (round $ x * clocksPerSecond)
429        finish  <- getCurrentTime
430        return $ VRat (toRational $ diffUTCTime start finish)
431op1 "mkdir" = guardedIO createDirectory
432op1 "rmdir" = guardedIO removeDirectory
433op1 "chdir" = guardedIO setCurrentDirectory
434op1 "graphs"= op1Cast (VInt . (genericLength :: String -> VInt)) -- XXX Wrong
435op1 "codes" = op1Cast (VInt . (genericLength :: String -> VInt))
436op1 "chars" = op1Cast (VInt . (genericLength :: String -> VInt))
437op1 "bytes" = op1Cast (VInt . (genericLength :: String -> VInt) . encodeUTF8)
438
439op1 "unlink" = \v -> do
440    vals <- fromVals v
441    rets <- mapM (doBoolIO removeFile) vals
442    return $ VInt $ sum $ map bool2n rets
443op1 "readdir" = \v -> do
444    path  <- fromVal v
445    files <- guardIO $ getDirectoryContents path
446    retSeq (map VStr files)
447op1 "slurp" = \v -> do
448    ifValTypeIsa v "IO"
449        (do h <- fromVal v
450            ifListContext (strictify $! op1 "=" v) $ do
451                content <- guardIO $ hGetContents h
452                return . VStr $ decodeUTF8 content)
453        (do
454            fileName    <- fromVal v
455            ifListContext
456                (slurpList fileName)
457                (slurpScalar fileName))
458    where
459    strictify action = do
460        VList lines <- action
461        return $ VList (length lines `seq` lines)
462    slurpList file = strictify $! op1 "=" (VList [VStr file])
463    slurpScalar file = do
464        content <- guardIO $ readFile file
465        return . VStr $ decodeUTF8 content
466op1 "opendir" = \v -> do
467    str <- fromVal v
468    dir <- guardIO $ openDirStream str
469    obj <- createObject (mkType "IO::Dir") []
470    return . VObject $ obj{ objOpaque = Just $ toDyn dir }
471op1 "IO::Dir::close" = op1 "IO::Dir::closedir"
472op1 "IO::Dir::closedir" = guardedIO (closeDirStream . fromObject)
473op1 "IO::Dir::rewind" = op1 "IO::Dir::rewinddir"
474op1 "IO::Dir::rewinddir" = guardedIO (rewindDirStream . fromObject)
475op1 "IO::Dir::read" = op1 "IO::Dir::readdir"
476op1 "IO::Dir::readdir" = \v -> do
477    dir <- fmap fromObject (fromVal v)
478    ifListContext
479        (retSeq =<< readDirStreamList dir)
480        (guardIO $ fmap (\x -> if null x then undef else castV x) $ readDirStream dir)
481    where
482    readDirStreamList dir = do
483        this <- tryIO "" $ readDirStream dir
484        if null this then return [] else do
485        rest <- readDirStreamList dir
486        return (VStr this:rest)
487op1 "Pugs::Internals::runShellCommand" = \v -> do
488    str <- fromVal v
489    cxt <- asks envContext
490    (res, exitCode) <- tryIO ("", ExitFailure (-1)) $ do
491        (inp,out,_,pid) <- runInteractiveCommand (encodeUTF8 str)
492        hClose inp
493        res             <- fmap (decodeUTF8 . deCRLF) $ hGetContents out
494        exitCode        <- waitForProcess pid
495        return (res, exitCode)
496    handleExitCode exitCode
497    return $ case cxt of
498        CxtSlurpy{} -> VList (map VStr $ lines res)
499        _           -> VStr res
500    where
501    -- XXX - crude CRLF treatment
502    deCRLF []                   = []
503    deCRLF ('\r':xs@('\n':_))   = xs
504    deCRLF (x:xs)               = (x:deCRLF xs)
505op1 "Pugs::Internals::runInteractiveCommand" = \v -> do
506    str <- fromVal v
507    guardIO $ do
508        (inp,out,err,pid) <- runInteractiveCommand str
509        return $ VList [ VHandle inp
510                       , VHandle out
511                       , VHandle err
512                       , VProcess (MkProcess pid)
513                       ]
514op1 "Pugs::Internals::check_for_io_leak" = \v -> do
515    rv      <- evalExp (App (Val v) Nothing [])
516    leaked  <- fromVal =<< op2Match rv (VType $ mkType "IO")
517    when leaked $ do
518        fail $ "BEGIN and CHECK blocks may not return IO handles,\n" ++
519               "as they would be invalid at runtime."
520    return rv
521op1 "run" = \v -> do
522    cmd         <- fromVal v
523    exitCode    <- tryIO (ExitFailure (-1)) $ system (encodeUTF8 cmd)
524    handleExitCode exitCode
525op1 "accept" = \v -> do
526    socket      <- fromVal v
527    (h, _, _)   <- guardIO $ accept socket
528    return $ VHandle h
529op1 "detach" = \v -> do
530    case v of
531        VThread thr -> do
532            stm $ tryPutTMVar (threadLock thr) undef
533            return $ VBool True
534        _           -> fail $ "Not a thread: " ++ show v
535op1 "kill" = \v -> do
536    case v of
537        VThread thr -> do
538            guardIO . killThread $ threadId thr
539            return $ VBool True
540        _           -> fail $ "Not a thread: " ++ show v
541op1 "join" = \v -> do
542    case v of
543        VThread thr -> stm $ takeTMVar (threadLock thr)
544        _           -> op2Join v (VList [])
545op1 "async" = \v -> do
546    env     <- ask
547    code    <- fromVal v
548    lock    <- stm $ newEmptyTMVar
549    tid     <- guardIO . forkIO $ do -- (if rtsSupportsBoundThreads then forkOS else forkIO) $ do
550        val <- runEvalIO env $ do
551            enterEvalContext CxtVoid $ App (Val code) Nothing []
552        stm $ tryPutTMVar lock val
553        return ()
554    return . VThread $ MkThread
555        { threadId      = tid
556        , threadLock    = lock
557        }
558--WV: async should return the thread id!    return undef
559op1 "listen" = \v -> do
560    port    <- fromVal v
561    socket  <- guardIO $ listenOn (PortNumber $ fromInteger port)
562    return $ VSocket socket
563op1 "flush" = guardedIO hFlush
564op1 "IO::close" = guardedIO hClose
565op1 "Socket::close" = guardedIO sClose
566op1 "Pair::key" = fmap fst . (fromVal :: Val -> Eval VPair)
567op1 "Pair::value" = \v -> do
568    ivar <- join $ doPair v pair_fetchElem
569    return . VRef . MkRef $ ivar
570op1 "pairs" = \v -> do
571    pairs <- pairsFromVal v
572    retSeq pairs
573op1 "List::kv" = \v -> do
574    pairs <- pairsFromVal v
575    kvs   <- forM pairs $ \(VRef ref) -> do
576        pair   <- readRef ref
577        fromVal pair
578    retSeq $ concat kvs
579op1 "Pair::kv" = op1 "List::kv"
580op1 "keys" = keysFromVal
581op1 "values" = valuesFromVal
582-- According to Damian
583-- (http://www.nntp.perl.org/group/perl.perl6.language/21895),
584-- =$obj should call $obj.next().
585op1 "="        = \v -> case v of
586    VObject _               -> evalExp $ App (_Var "&shift") (Just $ Val v) []
587    VRef (MkRef IArray{})   -> do
588        ifListContext
589            (fmap VList (join $ doArray v array_fetch))
590            (join $ doArray v array_shift)
591    _           -> op1 "readline" v
592op1 "readline" = op1Readline
593op1 "getc"     = op1Getc
594op1 "WHAT"     = fmap VType . evalValType
595op1 "List::end"   = \x -> fmap (castV . pred) (join $ doArray x array_fetchSize) -- monadic join
596op1 "List::elems" = \x -> fmap castV (join $ doArray x array_fetchSize) -- monadic join
597op1 "List::pop"   = \x -> join $ doArray x array_pop -- monadic join
598op1 "List::shift" = \x -> join $ doArray x array_shift -- monadic join
599op1 "pick"  = op1Pick
600op1 "sum"   = op1Sum
601op1 "min"   = op1Min
602op1 "max"   = op1Max
603op1 "uniq"  = op1Uniq
604op1 "chr"   = op1Cast (VStr . (:[]) . chr)
605op1 "ord"   = op1Cast $ \str -> if null str then undef else (castV . ord . head) str
606op1 "hex"   = fail "hex() is not part of Perl 6 - use :16() instead."
607op1 "oct"   = fail "oct() is not part of Perl 6 - use :8() instead."
608op1 "log"   = op1Floating log
609op1 "log10" = op1Floating (logBase 10)
610op1 "from"  = op1Cast (castV . matchFrom)
611op1 "to"    = op1Cast (castV . matchTo)
612op1 "matches" = op1Cast (VList . matchSubPos)
613op1 "gather" = \v -> do
614    evl <- asks envEval
615    evl (Syn "gather" [Val v])
616op1 "Thread::yield" = const $ do
617    guardSTM . unsafeIOToSTM $ yield
618    return $ VBool True
619op1 "DESTROYALL" = \x -> cascadeMethod id "DESTROY" x VUndef
620-- [,] is a noop -- It simply returns the input list
621op1 "prefix:[,]" = return
622op1 "prefix:$<<" = op1SigilHyper SScalar
623op1 "prefix:@<<" = op1SigilHyper SArray
624op1 "prefix:%<<" = op1SigilHyper SHash
625op1 "prefix:&<<" = op1SigilHyper SCode
626op1 "Code::assoc" = op1CodeAssoc
627op1 "Code::name"  = op1CodeName
628op1 "Code::arity" = op1CodeArity
629op1 "Code::body"  = op1CodeBody
630op1 "Code::pos"   = op1CodePos
631op1 "Code::signature" = op1CodeSignature
632op1 "IO::tell"    = \v -> do
633    h <- fromVal v
634    res <- guardIO $ hTell h
635    return $ VInt res
636op1 "Rat::numerator" = \(VRat t) -> return . VInt $ numerator t
637op1 "Rat::denominator" = \(VRat t) -> return . VInt $ denominator t
638op1 "TEMP" = \v -> do
639    ref <- fromVal v
640    val <- readRef ref
641    return . VCode $ mkPrim
642        { subBody = Prim . const $ do
643            writeRef ref val
644            retEmpty
645        }
646op1 "Pugs::Internals::hIsOpen" = op1IO hIsOpen
647op1 "Pugs::Internals::hIsClosed" = op1IO hIsClosed
648op1 "Pugs::Internals::hIsReadable" = op1IO hIsReadable
649op1 "Pugs::Internals::hIsWritable" = op1IO hIsWritable
650op1 "Pugs::Internals::hIsSeekable" = op1IO hIsSeekable
651op1 "Pugs::Internals::reduceVar" = \v -> do
652    str <- fromVal v
653    evalExp (_Var str)
654op1 "Pugs::Internals::rule_pattern" = \v -> do
655    case v of
656        VRule MkRulePGE{rxRule=re} -> return $ VStr re
657        VRule MkRulePCRE{rxRuleStr=re} -> return $ VStr re
658        _ -> fail $ "Not a rule: " ++ show v
659op1 "Pugs::Internals::rule_adverbs" = \v -> do
660    case v of
661        VRule MkRulePGE{rxAdverbs=hash} -> return hash
662        VRule MkRulePCRE{rxAdverbs=hash} -> return hash
663        _ -> fail $ "Not a rule: " ++ show v
664op1 "Pugs::Internals::current_pragma_value" = \v -> do
665    name <- fromVal v
666    prags <- asks envPragmas
667    return $ findPrag name prags
668    where
669        findPrag :: String -> [Pragma] -> Val
670        findPrag _ [] = VUndef
671        findPrag n (this:rest)
672            | n == pragName this = VInt $ toInteger $ pragDat this
673            | otherwise          = findPrag n rest
674op1 "Pugs::Internals::caller_pragma_value" = \v -> do
675    caller <- asks envCaller
676    case caller of
677        Just env -> local (const env) (op1 "Pugs::Internals::current_pragma_value" v)
678        _        -> return $ VUndef
679op1 "eager" = \v -> do
680    vlist <- fromVal v
681    return $! length (map valType vlist) `seq` VList vlist
682op1 "Pugs::Internals::emit_yaml" = \v -> do
683    glob <- filterPrim =<< asks envGlobal
684    yml  <- io $ showYaml (filterUserDefinedPad glob, v)
685    return $ VStr yml
686op1 "Object::HOW" = \v -> do
687    typ     <- evalValType v
688    evalExp $ _Var (':':'*':showType typ)
689op1 "Class::name" = \v -> do
690    cls     <- fromVal v
691    meta    <- readRef =<< fromVal cls
692    fetch   <- doHash meta hash_fetchVal
693    str     <- fromVal =<< fetch "name"
694    return str
695op1 "Class::traits" = \v -> do
696    cls     <- fromVal v
697    meta    <- readRef =<< fromVal cls
698    fetch   <- doHash meta hash_fetchVal
699    str     <- fromVal =<< fetch "is"
700    return str
701op1 "vv" = op1Cast VV
702op1 "stat" = \x -> opPerl5 "require File::stat; File::stat::stat" [x]
703op1 "lstat" = \x -> opPerl5 "require File::stat; File::stat::lstat" [x]
704op1 "Pugs::Internals::localtime"  = \x -> do
705    tz  <- io getCurrentTimeZone
706    tm  <- fromVal x    -- seconds since Perl's epoch
707    let utc   = posixSecondsToUTCTime (fromInteger tm + offset)
708        local = utcToLocalTime tz utc
709        day   = localDay local
710        tod   = localTimeOfDay local
711        (year, month, dayOfMonth)   = toGregorian day
712        (sec, pico)                 = properFraction $ todSec tod
713        (_, dayOfWeek)              = sundayStartWeek day
714    -- if wantString then return . VStr $ formatTime "%c" (ZonedTime local tz) else
715    retSeq [ vI    $ year
716           , vI    $ month
717           , vI    $ dayOfMonth
718           , vI    $ todHour tod
719           , vI    $ todMin tod
720           , VInt  $ sec
721           , vI    $ fromEnum (pico * 1000000000000)
722           , vI    $ dayOfWeek + 1
723           , vI    $ (monthAndDayToDayOfYear (isLeapYear year) month dayOfMonth) - 1
724           , VStr  $ timeZoneName tz
725           , vI    $ timeZoneMinutes tz * 60
726           , VBool $ timeZoneSummerOnly tz
727           ]
728    where
729    offset :: NominalDiffTime
730    offset = 946684800 -- diff between Haskell and Perl epochs (seconds)
731    vI :: Integral a => a -> Val
732    vI = VInt . toInteger
733
734op1 other   = \_ -> fail ("Unimplemented unaryOp: " ++ other)
735
736op1IO :: Value a => (Handle -> IO a) -> Val -> Eval Val
737op1IO = \fun v -> do
738    val <- fromVal v
739    fmap castV (guardIO $ fun val)
740
741op1SigilHyper :: VarSigil -> Val -> Eval Val
742op1SigilHyper sig val = do
743    vs <- fromVal val
744    evalExp $ Syn "," (map (\x -> Syn (shows sig "{}") [Val x]) vs)
745
746retSeq :: VList -> Eval Val
747retSeq xs = length xs `seq` return (VList xs)
748
749handleExitCode :: ExitCode -> Eval Val
750handleExitCode exitCode = do
751    glob    <- askGlobal
752    errSV   <- findSymRef (cast "$!") glob
753    writeRef errSV $ case exitCode of
754        ExitFailure x   -> VInt $ toInteger x
755        ExitSuccess     -> VUndef
756    return (VBool $ exitCode == ExitSuccess)
757
758cascadeMethod :: ([VStr] -> [VStr]) -> VStr -> Val -> Val -> Eval Val
759cascadeMethod f meth v args = do
760    typ     <- evalValType v
761    pkgs    <- fmap f (pkgParents $ showType typ)
762    named   <- case args of
763        VUndef -> return Map.empty
764        VType{}-> return Map.empty
765        _      -> join $ doHash args hash_fetch
766
767    -- Here syms is a list of (sym, tvar) tuples where tvar is the physical coderef
768    -- The monad in the "do" below is List.
769    syms <- forM pkgs $ \pkg -> do
770        let sym = cast $ ('&':pkg) ++ "::" ++ meth
771        maybeM (fmap (lookupPad sym) askGlobal) $ \ref -> do
772            return (sym, ref)
773
774    forM_ (nubBy (\(_, x) (_, y) -> x == y) (catMaybes syms)) $ \(sym, _) -> do
775        enterEvalContext CxtVoid $
776            App (Var sym) (Just $ Val v)
777                [ Syn "named" [Val (VStr key), Val val]
778                | (key, val) <- Map.assocs named
779                ]
780    return undef
781
782op1Return :: Eval Val -> Eval Val
783op1Return action = assertFrame FrameRoutine $ do
784    sub   <- fromVal =<< readVar (cast "&?ROUTINE")
785    -- If this is a coroutine, reset the entry point
786    case subCont sub of
787        Nothing -> action
788        Just tvar -> do
789            let thunk = (`MkThunk` anyType) . fix $ \redo -> do
790                evalExp $ subBody sub
791                stm $ writeTVar tvar thunk
792                redo
793            stm $ writeTVar tvar thunk
794            action
795
796op1Yield :: Eval Val -> Eval Val
797op1Yield action = assertFrame FrameRoutine $ do
798    sub   <- fromVal =<< readVar (cast "&?ROUTINE")
799    case subCont sub of
800        Nothing -> fail $ "cannot yield() from a " ++ pretty (subType sub)
801        Just tvar -> callCC $ \esc -> do
802            stm $ writeTVar tvar (MkThunk (esc undef) anyType)
803            action
804
805op1ShiftOut :: Val -> Eval Val
806op1ShiftOut v = retShift =<< do
807    evl <- asks envEval
808    evl $ case v of
809        VList [x]   -> Val x
810        _           -> Val v
811
812op1Exit :: Val -> Eval a
813op1Exit v = do
814    rv <- fromVal v
815    retControl . ControlExit $ if rv /= 0
816        then ExitFailure rv else ExitSuccess
817
818op1StrFirst :: (Char -> Char) -> Val -> Eval Val
819op1StrFirst f = op1Cast $ VStr .
820    \str -> case str of
821        []      -> []
822        (c:cs)  -> (f c:cs)
823
824-- op1Readline and op1Getc are precisely the implementation of op1 "readline"
825-- and op1 "getc", but those may be hidden in safe mode. We still want to use
826-- the functionality with the safe variants, hence these functions.
827op1Readline :: Val -> Eval Val
828op1Readline = \v -> op1Read v (io . getLines) getLine
829    where
830    getLines :: VHandle -> IO Val
831    getLines fh = unsafeInterleaveIO $ do
832        line <- doGetLine fh
833        case line of
834            Just str -> do
835                ~(VList rest) <- getLines fh
836                return $ VList (VStr str:rest)
837            _ -> return (VList [])
838    getLine :: VHandle -> Eval Val
839    getLine fh = do
840        line <- io $! doGetLine fh
841        case line of
842            Just str    -> return $! VStr $! (length str `seq` str)
843            _           -> return undef
844    doGetLine :: VHandle -> IO (Maybe VStr)
845    doGetLine fh = guardIOexcept [(isEOFError, Nothing)] $ do
846        line <- hGetLine fh
847        return . Just . decodeUTF8 $ line
848
849op1Getc :: Val -> Eval Val
850op1Getc = \v -> op1Read v (getChar) (getChar)
851    where
852    getChar :: VHandle -> Eval Val
853    getChar fh = guardIOexcept [(isEOFError, undef)] $ do
854        char <- hGetChar fh
855        str  <- getChar' fh char
856        return $ VStr $ decodeUTF8 str
857    -- We may have to read more than one byte, as one utf-8 char can span
858    -- multiple bytes.
859    getChar' :: VHandle -> Char -> IO String
860    getChar' fh char
861        | ord char < 0x80 = return [char]
862        | ord char < 0xE0 = readNmore 1
863        | ord char < 0xEE = readNmore 2
864        | ord char < 0xF5 = readNmore 3
865        | otherwise       = fail "Invalid utf-8 read by getc()"
866        where
867        readNmore :: Int -> IO String
868        readNmore n = do
869            new <- sequence $ replicate n (hGetChar fh)
870            return $ char:new
871
872{-|
873Read a char or a line from a handle.
874-}
875op1Read :: Val                   -- ^ The handle to read from (packed in a 'Val')
876        -> (VHandle -> Eval Val) -- ^ The function to call in list context
877        -> (VHandle -> Eval Val) -- ^ The function to call in item context
878        -> Eval Val              -- ^ The return value (a list of strings or a
879                                 --   string, packed in a 'Val')
880op1Read v fList fScalar = do
881    fh  <- handleOf v
882    ifListContext
883        (fList fh)
884        (fScalar fh)
885    where
886    handleOf x | safeMode, (VHandle h) <- x, h /= stdin = fail "Evil handle detected"
887    handleOf _ | safeMode = return stdin
888    handleOf VUndef = handleOf (VList [])
889    handleOf (VList []) = do
890        argsGV  <- readVar (cast "$*ARGS")
891        gv      <- fromVal argsGV
892        if defined gv
893            then handleOf gv
894            else do
895                args    <- readVar (cast "@*ARGS")
896                files   <- fromVal args
897                if null files
898                    then return stdin
899                    else do
900                        hdl <- handleOf (VStr (head files)) -- XXX wrong
901                        writeVar (cast "$*ARGS") (VHandle hdl)
902                        return hdl
903    handleOf (VStr x) = do
904        return =<< guardIO $ openFile x ReadMode
905    handleOf (VList [x]) = handleOf x
906    handleOf v = fromVal v
907
908bool2n :: Bool -> VInt
909bool2n v = if v
910  then 1
911  else 0
912
913doBoolIO :: Value a => (a -> IO b) -> Val -> Eval Bool
914doBoolIO f v = do
915    x <- fromVal v
916    tryIO False $ do
917        f x
918        return True
919
920guardedIO :: Value a => (a -> IO b) -> Val -> Eval Val
921guardedIO f v = do
922    x <- fromVal v
923    guardIO $ f x
924    return $ VBool True
925
926guardedIO2 :: (Value a, Value b)
927    => (a -> b -> IO c) -> Val -> Val -> Eval Val
928guardedIO2 f u v = do
929    x <- fromVal u
930    y <- fromVal v
931    guardIO $ f x y
932    return $ VBool True
933
934mapStr :: (Word8 -> Word8) -> [Word8] -> String
935mapStr f = map (chr . fromEnum . f)
936
937mapStr2 :: (Word8 -> Word8 -> Word8) -> [Word8] -> [Word8] -> String
938mapStr2 f x y = map (chr . fromEnum . uncurry f) $ x `zip` y
939
940mapStr2Fill :: (Word8 -> Word8 -> Word8) -> [Word8] -> [Word8] -> String
941mapStr2Fill f x y = map (chr . fromEnum . uncurry f) $ x `zipFill` y
942    where
943    zipFill [] [] = []
944    zipFill as [] = zip as (repeat 0)
945    zipFill [] bs = zip (repeat 0) bs
946    zipFill (a:as) (b:bs) = (a,b) : zipFill as bs
947
948op1Chomp :: VStr -> Val
949op1Chomp "" = VStr ""
950op1Chomp str
951    | last str == '\n'  = VStr (init str)
952    | otherwise         = VStr str
953
954perlReplicate :: VInt -> a -> [a]
955perlReplicate = genericReplicate . max 0
956
957-- XXX only used at    op2 "?^"   because my Haskell is too poor - ferreira
958neBool :: VBool -> VBool -> VBool
959neBool = (==) . not
960
961-- |Implementation of 2-arity primitive operators and functions
962op2 :: String -> Val -> Val -> Eval Val
963op2 "rename" = guardedIO2 rename
964op2 "symlink" = guardedIO2 createSymbolicLink
965op2 "link" = guardedIO2 createLink
966op2 "*"  = op2Numeric (*)
967op2 "/"  = op2Divide
968op2 "%"  = op2Modulus
969op2 "x"  = op2Cast (\x y -> VStr . concat $ (y :: VInt) `perlReplicate` x)
970op2 "xx" = op2Cast (\x y -> VList . concat $ (y :: VInt) `perlReplicate` x)
971op2 "+&" = op2Int (.&.)
972op2 "+<" = op2Int shiftL
973op2 "+>" = op2Int shiftR
974op2 "~&" = op2Str $ mapStr2 (.&.)
975op2 "~<" = op2Cast (\x y -> VStr $ mapStr (`shiftL` y) x)
976op2 "~>" = op2Cast (\x y -> VStr $ mapStr (`shiftR` y) x)
977op2 "**" = op2Exp
978op2 "+"  = op2Numeric (+)
979op2 "-"  = op2Numeric (-)
980op2 "atan" = op2Num atan2
981op2 "~"  = op2Str (++)
982op2 "+|" = op2Int (.|.)
983op2 "+^" = op2Int xor
984op2 "~|" = op2Str $ mapStr2Fill (.|.)
985op2 "?|" = op2Bool (||)
986op2 "?&" = op2Bool (&&)
987op2 "~^" = op2Str $ mapStr2Fill xor
988op2 "?^" = op2Bool neBool -- for bools, 'xor' is the same as '!=='
989op2 "=>" = \x y -> return $ castV (x, y)
990op2 "="  = \x y -> evalExp (Syn "=" [Val x, Val y])
991op2 "cmp"= op2OrdNumStr
992op2 "leg"= op2Ord vCastStr
993op2 "<=>"= op2OrdNumeric compare
994op2 ".." = op2Range
995op2 "..^" = op2RangeExclRight
996op2 "^.." = op2RangeExclLeft
997op2 "^..^" = op2RangeExclBoth
998op2 "!=" = op2OrdNumeric (/=)
999op2 "==" = op2OrdNumeric (==)
1000op2 "<"  = op2OrdNumeric (<)
1001op2 "<=" = op2OrdNumeric (<=)
1002op2 ">"  = op2OrdNumeric (>)
1003op2 ">=" = op2OrdNumeric (>=)
1004op2 "ne" = op2Cmp vCastStr (/=)
1005op2 "eq" = op2Cmp vCastStr (==)
1006op2 "lt" = op2Cmp vCastStr (<)
1007op2 "le" = op2Cmp vCastStr (<=)
1008op2 "gt" = op2Cmp vCastStr (>)
1009op2 "ge" = op2Cmp vCastStr (>=)
1010op2 "~~" = op2Match
1011op2 "=:=" = \x y -> do
1012    return $ castV $ case x of
1013        VRef xr | VRef yr <- y ->
1014            -- Take advantage of the pointer address built-in with (Show VRef)
1015            show xr == show yr
1016        _   ->
1017            W# (unsafeCoerce# x :: Word#) == W# (unsafeCoerce# y :: Word#)
1018op2 "===" = \x y -> do
1019    return $ castV (x == y)
1020op2 "eqv" = op2Identity -- XXX wrong, needs to compare full objects
1021op2 "&&" = op2Logical (fmap not . fromVal)
1022op2 "||" = op2Logical (fmap id . fromVal)
1023op2 "^^" = \x y -> do
1024    let xor True True   = VBool False
1025        xor True False  = x
1026        xor False True  = y
1027        xor False False = VBool False
1028    op2Cast xor x y
1029op2 "//" = op2Logical (return . defined)
1030op2 ".[]" = \x y -> do
1031    evl <- asks envEval
1032    evl $ Syn "[]" [Val x, Val y]
1033op2 ".{}" = \x y -> do
1034    evl <- asks envEval
1035    evl $ Syn "{}" [Val x, Val y]
1036-- XXX pipe forward XXX
1037op2 "and"= op2 "&&"
1038op2 "or" = op2 "||"
1039op2 "xor"= op2 "^^"
1040op2 "orelse"= op2 "//"  -- XXX wrong
1041op2 "andthen"= op2 "&&" -- XXX even wronger
1042op2 "pick" = op2Pick
1043op2 "grep" = op2Grep
1044op2 "first" = op2First
1045op2 "map"  = op2Map
1046op2 "join" = op2Join
1047op2 "reduce" = op2ReduceL False
1048op2 "produce" = op2ReduceL True
1049op2 "reverse" = op2MaybeListop (VList . reverse) (VStr . reverse)
1050op2 "chomp" = op2MaybeListop (VList . map op1Chomp) op1Chomp
1051op2 "kill" = \s v -> do
1052    sig  <- fromVal s
1053    pids <- fromVals v
1054    sig' <- fromVal sig
1055    pids'<- mapM fromVal pids
1056    let doKill pid = do
1057        signalProcess (toEnum sig') (toEnum pid)
1058        return 1
1059    rets <- mapM (tryIO 0 . doKill) pids'
1060    return . VInt $ sum rets
1061op2 "isa"    = \x y -> do
1062    typY <- case y of
1063        VStr str -> return $ mkType str
1064        _        -> fromVal y
1065    typX <- fromVal x -- XXX consider line 224 of Pugs.Prim.Match case too
1066    typs <- pkgParentClasses (showType typX)
1067    return . VBool $ showType typY `elem` (showType typX:typs)
1068op2 "does"   = \x y -> do
1069    typY <- case y of
1070        VStr str -> return $ mkType str
1071        _        -> fromVal y
1072    op2Match x (VType typY)
1073op2 "delete" = \x y -> do
1074    ref <- fromVal x
1075    rv  <- deleteFromRef ref y
1076    -- S29: delete always returns the full list regardless of context.
1077    return $ case rv of
1078        VList [x]   -> x
1079        _           -> rv
1080op2 "exists" = \x y -> do
1081    ref <- fromVal x
1082    fmap VBool (existsFromRef ref y)
1083op2 "unshift" = op2Array array_unshift
1084op2 "push" = op2Array array_push
1085op2 "split" = op2Split
1086op2 "Str::split" = flip op2Split
1087op2 "connect" = \x y -> do
1088    host <- fromVal x
1089    port <- fromVal y
1090    hdl  <- guardIO $ connectTo host (PortNumber $ fromInteger port)
1091    return $ VHandle hdl
1092op2 "Pugs::Internals::hSetBinaryMode" = \x y -> do
1093    fh    <- fromVal x
1094    mode  <- fromVal y
1095    guardIO $ hSetBinaryMode fh mode
1096    return $ VBool True
1097op2 "Pugs::Internals::openFile" = \x y -> do
1098    filename <- fromVal x
1099    mode     <- fromVal y
1100    hdl      <- guardIO $ do
1101        h <- openFile filename (modeOf mode)
1102        hSetBuffering h NoBuffering
1103        return h
1104    return $ VHandle hdl
1105    where
1106    modeOf "r"  = ReadMode
1107    modeOf "w"  = WriteMode
1108    modeOf "a"  = AppendMode
1109    modeOf "rw" = ReadWriteMode
1110    modeOf m    = error $ "unknown mode: " ++ m
1111op2 "exp" = \x y -> if defined y
1112    then op2Num (**) x y
1113    else op1Floating exp x
1114op2 "Pugs::Internals::sprintf" = \x y -> do
1115    -- a single argument is all Haskell can really handle.
1116    -- XXX printf should be wrapped in a catch so a mis-typed argument
1117    -- doesnt kill pugs with a runtime exception.
1118    -- XXX fail... doesnt?!
1119    str <- fromVal x
1120    arg <- fromVal y
1121    return $ VStr $ case arg of
1122       VNum n -> printf str n
1123       VRat r -> printf str ((fromRational r)::Double)
1124       VInt i -> printf str i
1125       VStr s -> printf str s
1126       _      -> fail "should never be reached given the type declared below"
1127op2 "run" = \x y -> do
1128    prog        <- fromVal x
1129    args        <- fromVals y
1130    exitCode    <- tryIO (ExitFailure (-1)) $
1131        rawSystem (encodeUTF8 prog) (map encodeUTF8 args)
1132    handleExitCode exitCode
1133op2 "crypt" = \x y -> opPerl5 "crypt" [x, y]
1134op2 "chmod" = \x y -> do
1135    mode  <- fromVal x
1136    files <- fromVals y
1137    rets  <- mapM (doBoolIO . flip setFileMode $ toEnum mode) files
1138    return . VInt . sum $ map bool2n rets
1139op2 "splice" = \x y -> do
1140    fetchSize   <- doArray x array_fetchSize
1141    len'        <- fromVal y
1142    sz          <- fetchSize
1143    let len = if len' < 0 then if sz > 0 then (len' `mod` sz) else 0 else len'
1144    op4 "splice" x y (castV (sz - len)) (VList [])
1145op2 "sort" = \x y -> do
1146    xs <- fromVals x
1147    ys <- fromVals y
1148    op1 "sort" . VList $ xs ++ ys
1149op2 "IO::say" = op2Print True
1150op2 "IO::print" = op2Print False
1151op2 "printf" = op3 "IO::printf" (VHandle stdout)
1152op2 "BUILDALL" = cascadeMethod reverse "BUILD"
1153op2 "Pugs::Internals::install_pragma_value" = \x y -> do
1154    name <- fromVal x
1155    val  <- fromVal y
1156    idat <- asks envInitDat
1157    idatval <- stm $ readTVar idat
1158    --trace ("installing " ++ name ++ "/" ++ (show val)) $ return ()
1159    let prag = initPragmas idatval
1160    stm $ writeTVar idat idatval{initPragmas =
1161        MkPrag{ pragName=name, pragDat=val } : prag }
1162    return (VBool True)
1163op2 "Pugs::Internals::base" = \x y -> do
1164    base <- fromVal x
1165    case y of
1166        VRef{}  -> op2BasedDigits base =<< fromVal y
1167        VList{} -> op2BasedDigits base =<< fromVal y
1168        _       -> do
1169            str <- fromVal y
1170            op2BasedDigits base [ s | Just s <- map baseDigit str ]
1171op2 "HOW::does" = \t p -> do
1172    meta    <- readRef =<< fromVal t
1173    fetch   <- doHash meta hash_fetchVal
1174    name    <- fromVal =<< fetch "name"
1175    roles   <- fromVals p
1176    mixinRoles name roles
1177    return undef
1178
1179op2 ('!':name) = \x y -> op1Cast (VBool . not) =<< op2 name x y
1180op2 other = \_ _ -> fail ("Unimplemented binaryOp: " ++ other)
1181
1182baseDigit :: Char -> Maybe Val
1183baseDigit '.'       = return (VStr ".")
1184baseDigit ch | ch >= '0' && ch <= '9' = return (castV (ord ch - ord '0'))
1185baseDigit ch | ch >= 'a' && ch <= 'z' = return (castV (ord ch - ord 'a' + 10))
1186baseDigit ch | ch >= 'A' && ch <= 'Z' = return (castV (ord ch - ord 'A' + 10))
1187baseDigit _         = Nothing
1188
1189op2BasedDigits :: VInt -> [Val] -> Eval Val
1190op2BasedDigits base vs
1191    | null post = do
1192        pre' <- mapM fromVal pre
1193        return $ VInt (asIntegral pre')
1194    | otherwise = do
1195        pre'  <- mapM fromVal pre
1196        post' <- mapM fromVal $ tail post
1197        return $ VRat (asFractional (0:post') + (asIntegral pre' % 1))
1198    where
1199    (pre, post) = break (== VStr ".") $ filter (/= VStr "_") vs
1200    asIntegral = foldl (\x d -> base * x + d) 0
1201    asFractional :: [VInt] -> VRat
1202    asFractional = foldr (\d x -> (x / (base % 1)) + (d % 1)) (0 % 1)
1203
1204op2Print :: Bool -> Val -> Val -> Eval Val
1205op2Print wantNewline h v = do
1206    handle <- fromVal h
1207    strs   <- mapM fromVal =<< case v of
1208        VList vs  -> return vs
1209        _         -> return [v]
1210    guardIO $ do
1211        forM_ strs (hPutStr handle . encodeUTF8)
1212        when wantNewline (hPutStr handle "\n")
1213        return $ VBool True
1214
1215op2Split :: Val -> Val -> Eval Val
1216op2Split x y = do
1217    val <- fromVal x
1218    str <- fromVal y
1219    case val of
1220        VRule rx -> do
1221            chunks <- rxSplit rx str
1222            return $ VList chunks
1223        _ -> do
1224            delim <- fromVal val
1225            return $ split' delim str
1226    where
1227    split' :: VStr -> VStr -> Val
1228    split' [] xs = VList $ map (VStr . (:[])) xs
1229    split' glue xs = VList $ map VStr $ split glue xs
1230
1231op2MaybeListop :: forall tlist titem. (Value tlist, Value [tlist], Value titem) =>
1232    ([tlist] -> Val) -> (titem -> Val) -> Val -> Val -> Eval Val
1233op2MaybeListop flist fitem lead rest = case lead of
1234    VList{} -> do
1235        lead' <- fromVal lead
1236        rest' <- fromVal rest
1237        return (flist $ lead' ++ rest')
1238    VRef ref -> do
1239        vs      <- fromVal =<< readRef ref
1240        vlist   <- fromVal rest
1241        return (flist $ vs ++ vlist)
1242    _ | VList [] <- rest -> do
1243        -- Probably a single item.
1244        item    <- fromVal lead
1245        return (fitem item)
1246    _ -> do
1247        lead'   <- fromVal lead
1248        rest'   <- fromVal rest
1249        return (flist (lead':rest'))
1250
1251-- |Implementation of 3-arity primitive operators and functions
1252op3 :: String -> Val -> Val -> Val -> Eval Val
1253op3 "Pugs::Internals::exec" = \x y z -> do
1254    prog        <- fromVal x
1255    shell       <- fromVal y
1256    args        <- fromVals z
1257    exitCode    <- guardIO $ executeFile' prog shell args Nothing
1258    rv          <- handleExitCode exitCode
1259    when (rv == VBool True) $ do
1260        guardIO $ exitWith ExitSuccess
1261    return rv
1262op3 "Pugs::Internals::caller" = \x y z -> do
1263    --kind <- fromVal =<< op1 "WHAT" x
1264    kind <- case x of
1265        VStr str -> return $ mkType str
1266        _        -> fromVal x
1267    skip <- fromVal y
1268    when (skip < 0) $ do
1269        fail "Pugs::Internals::caller called with negative skip"
1270    label <- fromVal z
1271    op3Caller kind skip label
1272op3 "index" = \x y z -> do
1273    str <- fromVal x
1274    sub <- fromVal y
1275    pos <- fromVal z
1276    return . VInt $ doIndex 0 str sub pos
1277    where
1278    doIndex :: VInt -> VStr -> VStr -> VInt -> VInt
1279    doIndex n a b p
1280        | p > 0, null a     = doIndex n a b 0
1281        | p > 0             = doIndex (n+1) (tail a) b (p-1)
1282        | b `isPrefixOf` a  = n
1283        | null a            = -1
1284        | otherwise         = doIndex (n+1) (tail a) b 0
1285op3 "rindex" = \x y z -> do
1286    str <- fromVal x
1287    sub <- fromVal y
1288    pos <- fromVal z
1289    let skip | defined z = length str - pos - length sub
1290             | otherwise = 0
1291    return . VInt $ doRindex str sub skip
1292    where
1293    doRindex :: VStr -> VStr -> Int -> VInt
1294    doRindex a b skip
1295        | skip > 0         = doRindex (init a) b (skip-1)
1296        | b `isSuffixOf` a = toInteger $ length a - length b
1297        | null a           = -1
1298        | otherwise        = doRindex (init a) b 0
1299
1300op3 "splice" = \x y z -> do
1301    op4 "splice" x y z (VList [])
1302op3 "split" = op3Split
1303op3 "Str::split" = \x y z -> do
1304    op3 "split" y x z
1305op3 "HOW::new" = \t n p -> do
1306    cls     <- op3 "Object::new" t n p
1307    meta    <- readRef =<< fromVal cls
1308    fetch   <- doHash meta hash_fetchVal
1309
1310    attrs   <- fetch "attrs"
1311
1312    name    <- fromVal =<< fetch "name" :: Eval String
1313    roles   <- fromVals =<< fetch "does" :: Eval [String]
1314    supers  <- fromVals =<< fetch "is" :: Eval [String]
1315
1316    -- Role flattening -- copy over things there and put it to symbol table
1317    -- XXX - also do renaming of concrete types mentioned in roles
1318    -- XXX - also, rewrite subEnv mentioned in the subs
1319    -- XXX - also, copy over the inheritance chain from role's metaobject
1320    mixinRoles name roles
1321
1322    -- Merge in slot definitions in "attrs"
1323    defs        <- join $ doHash attrs hash_fetch
1324    parentAttrs <- forM (roles ++ supers) $ fetchMetaInfo "attrs"
1325    store       <- doHash attrs hash_store
1326    store $ Map.unions (defs:parentAttrs)
1327   
1328    return cls
1329
1330op3 "Object::new" = \t n p -> do
1331    positionals <- fromVal p
1332    typ     <- fromVal t
1333    named   <- fromVal n
1334
1335    defs    <- fetchMetaInfo "attrs" (showType typ)
1336    attrs   <- io $ H.new (==) H.hashString
1337    writeIVar (IHash attrs) (named `Map.union` defs)
1338    uniq    <- newObjectId
1339    unless (positionals == VList []) (fail "Must only use named arguments to new() constructor\nBe sure to use bareword keys.")
1340    let obj = VObject $ MkObject
1341            { objType   = typ
1342            , objAttrs  = attrs
1343            , objId     = uniq
1344            , objOpaque = Nothing
1345            }
1346    -- Now start calling BUILD for each of parent classes (if defined)
1347    op2 "BUILDALL" obj $ (VRef . hashRef) named
1348    -- Register finalizers by keeping weakrefs somehow
1349    setFinalization obj
1350
1351op3 "Object::clone" = \t n _ -> do
1352    named <- fromVal n
1353    (VObject o) <- fromVal t
1354    attrs   <- readIVar (IHash $ objAttrs o)
1355    attrs'  <- io $ H.new (==) H.hashString
1356    uniq    <- newObjectId
1357    writeIVar (IHash attrs') (named `Map.union` attrs)
1358    return $ VObject o{ objAttrs = attrs', objId = uniq }
1359
1360op3 "Pugs::Internals::hSeek" = \x y z -> do
1361    handle <- fromVal x
1362    pos <- fromVal y
1363    mode <- fromVal z
1364    guardIO $ hSeek handle (modeOf mode) pos
1365    retEmpty
1366    where
1367        modeOf :: Int -> SeekMode
1368        modeOf 0 = AbsoluteSeek
1369        modeOf 1 = RelativeSeek
1370        modeOf 2 = SeekFromEnd
1371        modeOf m = error ("Unknown seek mode: " ++ (show m))
1372op3 "IO::printf" = \x y z -> do
1373    rv      <- evalExp $ App (_Var "&sprintf") Nothing [Val y, Val z]
1374    op2Print False x rv
1375op3 other = \_ _ _ -> fail ("Unimplemented 3-ary op: " ++ other)
1376
1377mixinRoles :: String -> [String] -> Eval ()
1378mixinRoles name roles = do
1379    glob    <- asks envGlobal
1380    let rolePkgs = map cast roles
1381        thisPkg  = cast name
1382
1383    stm . modifyMPad glob $ \(MkPad entries) ->
1384        MkPad . Map.unionWith mergePadEntry entries . Map.fromList $
1385            [ (k{ v_package = thisPkg }, v)
1386            | (k, v) <- Map.assocs entries
1387            , v_package k `elem` rolePkgs
1388            ]
1389
1390op3Split :: Val -> Val -> Val -> Eval Val
1391op3Split x y z = do
1392    val <- fromVal x
1393    str <- fromVal y
1394    limit <- fromVal z
1395    case val of
1396        VRule rx -> do
1397            chunks <- rxSplit_n rx str limit
1398            return $ VList chunks
1399        _ -> do
1400            delim <- fromVal val
1401            return $ split' delim str limit
1402    where
1403    split' :: VStr -> VStr -> Int -> Val
1404    split' [] xs n = VList $ (map (VStr . (:[])) (take (n-1) xs)) ++ [ VStr $ drop (n-1) xs ]
1405    split' glue xs n = VList $ map VStr $ split_n glue xs n
1406
1407-- XXX - The "String" below wants to be Type.
1408fetchMetaInfo :: Value a => String -> [Char] -> Eval a
1409fetchMetaInfo key typ = do
1410    meta    <- readRef =<< fromVal =<< evalExp (_Var (':':'*':typ))
1411    fetch   <- doHash meta hash_fetchVal
1412    fromVal =<< fetch key
1413
1414-- |Implementation of 4-arity primitive operators and functions.
1415-- Only substr and splice
1416op4 :: String -> Val -> Val -> Val -> Val -> Eval Val
1417op4 "substr" = \x y z w -> do
1418    str  <- fromVal x
1419    pos  <- fromVal y
1420    lenP <- fromVal z
1421    let len | defined z = lenP
1422            | otherwise = length str
1423        (pre, result, post) = doSubstr str pos len
1424    let change = \new -> do
1425        var <- fromVal x
1426        rep <- fromVal new
1427        writeRef var (VStr $ concat [pre, rep, post])
1428    -- If the replacement is given in w, change the str.
1429    when (defined w && not (defined result)) $ change w
1430    -- Return a proxy which will modify the str if assigned to.
1431    return $ VRef . MkRef $ proxyScalar (return result) change
1432    where
1433    doSubstr :: VStr -> Int -> Int -> (VStr, Val, VStr)
1434    doSubstr str pos len
1435        | abs pos > length str = ("", VUndef, "")
1436        | pos < 0   = doSubstr str (length str + pos) len
1437        | len < 0   = doSubstr str pos (length str - pos + len)
1438        | otherwise = ((take pos str), VStr (take len $ drop pos str), (drop (pos + len) str))
1439
1440-- op4 "splice" = \x y z w-> do
1441op4 "splice" = \x y z w -> do
1442    splice  <- doArray x array_splice
1443    start   <- fromVal y
1444    count   <- fromVal z
1445    vals    <- fromVals w
1446    vals'   <- splice start count vals
1447    return $ VList vals'
1448
1449op4 other = \_ _ _ _ -> fail ("Unimplemented 4-ary op: " ++ other)
1450
1451op1Range :: Val -> Eval Val
1452op1Range (VStr s)    = return . VList $ map VStr $ strRangeInf s
1453op1Range (VRat n)    = return . VList $ map VRat [n ..]
1454op1Range (VNum n)    = return . VList $ map VNum [n ..]
1455op1Range (VInt n)    = return . VList $ map VInt [n ..]
1456op1Range x           = do
1457    int <- fromVal x
1458    op1Range (VInt int)
1459
1460{- In the four op2Range* functions below, rationals
1461have to be handled separately because Haskell ranges
1462are different from Perl 6 ranges.  For example,
1463in Haskell, [1.1 .. 2] will return [1.1,2.1].  So, we
1464run the elements through a filter to ensure that the
1465upper bound is satisfied
1466-}
1467op2Range :: Val -> Val -> Eval Val
1468op2Range (VStr s) y  = do
1469    y'  <- fromVal y
1470    return . VList $ map VStr $ strRange s y'
1471op2Range (VNum n) y  = do
1472    y'  <- fromVal y
1473    return . VList $ map VNum [n .. y']
1474op2Range x (VNum n)  = do
1475    x'  <- fromVal x
1476    return . VList $ map VNum [x' .. n]
1477op2Range (VRat n) y  = do
1478    y'  <- fromVal y
1479    return . VList $ map VRat (filter (<= y') [n .. y'])
1480op2Range x (VRat n)  = do
1481    x'  <- fromVal x
1482    return . VList $ map VRat (filter (<= n) [x' .. n])
1483op2Range x y         = do
1484    x'  <- fromVal x
1485    y'  <- fromVal y
1486    return . VList $ map VInt [x' .. y']
1487
1488-- because the right-exclusivity of a range can leave it
1489-- with no remaining elements, we need to check before
1490-- removing an element when enforcing left-exclusivity
1491removeRangeFirst :: [Val] -> [Val]
1492removeRangeFirst vals = if null vals then vals else init vals
1493
1494op2RangeExclRight :: Val -> Val -> Eval Val
1495op2RangeExclRight (VRat n) y  = do
1496    y' <- fromVal y
1497    return . VList $ map VRat (filter (< y') [n .. y'])
1498op2RangeExclRight x (VRat n)  = do
1499    x'  <- fromVal x
1500    return . VList $ map VRat (filter (< n) [x' .. n])
1501op2RangeExclRight x y = do
1502    VList vals <- op2Range x y
1503    return . VList $ removeRangeFirst vals
1504
1505op2RangeExclLeft :: Val -> Val -> Eval Val
1506op2RangeExclLeft (VRat n) y  = do
1507    y'  <- fromVal y
1508    return . VList $ map VRat (filter (\v -> n < v && v <= y') [n .. y'])
1509op2RangeExclLeft x (VRat n)  = do
1510    x'  <- fromVal x
1511    return . VList $ map VRat (filter (\v -> x' < v && v <= n) [x' .. n])
1512op2RangeExclLeft x y = do
1513    VList vals <- op2Range x y
1514    return . VList $ tail vals
1515
1516op2RangeExclBoth :: Val -> Val -> Eval Val
1517op2RangeExclBoth (VRat n) y  = do
1518    y'  <- fromVal y
1519    return . VList $ map VRat (filter (\v -> n < v && v < y') [n .. y'])
1520op2RangeExclBoth x (VRat n)  = do
1521    x'  <- fromVal x
1522    return . VList $ map VRat (filter (\v -> x' < v && v < n) [x' .. n])
1523op2RangeExclBoth x y = do
1524    VList vals <- op2Range x y
1525    return . VList $ removeRangeFirst (tail vals)
1526
1527op2ChainedList :: Val -> Val -> Val
1528op2ChainedList x y
1529    | VList xs <- x, VList ys <- y  = VList $ xs ++ ys
1530    | VList xs <- x                 = VList $ xs ++ [y]
1531    | VList ys <- y                 = VList (x:ys)
1532    | otherwise                     = VList [x, y]
1533
1534op2Logical :: (Val -> Eval Bool) -> Val -> Val -> Eval Val
1535op2Logical f x y = do
1536    ok <- f x
1537    if ok then return x else do
1538    ref <- fromVal y
1539    forceRef ref
1540
1541op2Identity :: Val -> Val -> Eval Val
1542op2Identity (VObject x) (VObject y) = return $ VBool (objId x == objId y)
1543op2Identity (VRef ref) y = do
1544    x <- readRef ref
1545    op2Identity x y
1546op2Identity x (VRef ref) = do
1547    y <- readRef ref
1548    op2Identity x y
1549op2Identity x y = do
1550    return $ VBool (x == y)
1551
1552op2Cmp :: (a -> Eval b) -> (b -> b -> VBool) -> a -> a -> Eval Val
1553op2Cmp f cmp x y = do
1554    x' <- f x
1555    y' <- f y
1556    return $ VBool $ x' `cmp` y'
1557
1558op2Ord :: (Ord ord) => (Val -> Eval ord) -> Val -> Val -> Eval Val
1559op2Ord f x y = withDefined [x, y] $ do
1560    x' <- f x
1561    y' <- f y
1562    return $ VInt $ case x' `compare` y' of
1563        LT -> -1
1564        EQ -> 0
1565        GT -> 1
1566
1567isNumeric :: Val -> Bool
1568isNumeric (VNum {}) = True
1569isNumeric (VRat {}) = True
1570isNumeric (VInt {}) = True
1571isNumeric _ = False
1572
1573op2OrdNumStr :: Val -> Val -> Eval Val
1574op2OrdNumStr x y
1575    | isNumeric x && isNumeric y = op2Ord vCastRat x y
1576    | otherwise                  = op2Ord vCastStr x y
1577
1578op3Caller :: Type -> Int -> Val -> Eval Val
1579--op3Caller kind skip label = do
1580op3Caller kind skip _ = do                                 -- figure out label
1581    chain <- callChain =<< ask
1582    formatFrame $ filter labelFilter $ drop skip $ filter kindFilter chain
1583    where
1584    formatFrame :: [(Env, Maybe VCode)] -> Eval Val
1585    formatFrame [] = retEmpty
1586    formatFrame ((env, Just sub):_) = retSeq
1587        [ VStr $ cast (envPackage env)                 -- .package
1588        , VStr $ cast (posName $ envPos env)           -- .file
1589        , VInt $ toInteger $ posBeginLine $ envPos env -- .line
1590        , VStr $ cast (subName sub)                    -- .subname
1591        , VStr $ show $ subType sub                    -- .subtype
1592        , VCode $ sub                                  -- .sub
1593        -- TODO: add more things as they are specced.
1594        ]
1595    formatFrame ((env, _):_) = retSeq
1596        [ VStr $ cast (envPackage env)                 -- .package
1597        , VStr $ cast (posName $ envPos env)           -- .file
1598        , VInt $ toInteger $ posBeginLine $ envPos env -- .line
1599        ]
1600    kindFilter :: (Env, Maybe VCode) -> Bool
1601    kindFilter (_, Just sub) =
1602        case (showType kind, subType sub) of
1603            ("Any",      _)          -> True  -- I hope this is optimized
1604            ("Method",   SubMethod)  -> True
1605            ("Sub",      SubRoutine) -> True
1606            ("Block",    SubBlock)   -> True
1607            ("Block",    SubPointy)  -> True
1608            (_,          _)          -> False
1609    kindFilter _ = kind == anyType
1610    labelFilter _ = True                             -- TODO: figure out how
1611    callChain :: Env -> Eval [(Env, Maybe VCode)]
1612    callChain cur =
1613        case envCaller cur of
1614            Just caller -> do
1615                val <- local (const caller) (readVar $ cast "&?ROUTINE")
1616                if (val == undef) then return [(caller, Nothing)] else do
1617                sub <- fromVal val
1618                rest <- callChain caller
1619                return ((caller, Just sub) : rest)
1620            _           -> return []
1621
1622
1623opPerl5 :: String -> [Val] -> Eval Val
1624opPerl5 sub args = do
1625    env     <- ask
1626    envSV   <- io $ mkEnv env
1627    let prms = map (\i -> "$_[" ++ show i ++ "]") [0 .. (length args - 1)]
1628    subSV   <- io $ evalPerl5 ("sub { " ++ sub ++ "(" ++ (concat $ intersperse ", " prms) ++ ") }") envSV (enumCxt cxtItemAny)
1629    argsSV  <- mapM fromVal args
1630    runInvokePerl5 subSV nullSV argsSV
1631
1632evalPerl5WithCurrentEnv :: String -> Eval Val
1633evalPerl5WithCurrentEnv code = do
1634    env     <- ask
1635    guardIO $ do
1636        envSV   <- mkEnv env
1637        sv      <- evalPerl5 code envSV $ enumCxt cxtItemAny
1638        return (PerlSV sv)
1639
1640atomicEval :: Eval Val -> Eval Val
1641atomicEval action = do
1642    env <- ask
1643    if envAtomic env then action else do
1644        rv <- guardSTM (runEvalSTM env action)
1645        case rv of
1646            VError{}    -> retShift rv
1647            VControl{}  -> retShift rv
1648            _           -> return rv
1649
1650{-| Assert that a list of Vals is all defined.
1651This should 'fail' (in the Perl sense).
1652
1653TOTHINK: report which element in the input list was the one
1654triggering the failure. Just zipping with [1 ..] may not be
1655enough because our caller may not be passing through its own
1656input args in the same order and position to us.
1657
1658-}
1659withDefined :: (Monad m) => [Val] -> m a -> m a
1660withDefined [] c = c
1661withDefined (VUndef:_) _  = fail "use of uninitialized value"
1662withDefined (VType{}:_) _ = fail "use of uninitialized value"
1663withDefined (_:xs) c = withDefined xs c
1664
1665-- |Returns a transaction to install a primitive operator using
1666-- 'Pugs.AST.genMultiSym'.
1667-- The associativity determines the arity and fixity of ops.
1668-- The primitive\'s subBody is defined in 'op0', 'op1', etc depending on arity,
1669-- the default is 'op0'.
1670-- The Pad symbol name is prefixed with \"&*\" for functions and
1671-- \"&*\" ~ fixity ~ \":\" for operators.
1672primOp :: String -> String -> Params -> String -> Bool -> Bool -> Bool -> STM PadMutator
1673primOp sym assoc prms ret isSafe isMacro isExport = fullEval $ do
1674    prim <- genMultiSym var (sub (isSafe || not safeMode)) mempty
1675    case assoc of
1676        -- Manufacture &infix:<!===> from &infix:<===>.
1677        "chain" | head sym /= '!' -> do
1678            prim' <- primOp ('!':sym) assoc prms ret isSafe isMacro isExport
1679            return (prim . prim')
1680        _       | isExport -> do
1681            -- Here we rewrite a multi form that redispatches into the method form.
1682            prim' <- genMultiSym (var{ v_package = emptyPkg }) (sub (isSafe || not safeMode)) mempty
1683            return (prim . prim')
1684        _       -> return prim
1685    where
1686    -- It is vital that we generate the ID for the Var for all the primitives at once,
1687    -- otherwise they'll be generated unpredictably during runtime with an as-needed basis,
1688    -- which may introduce race conditions under e.g. anotmer atomic block.
1689    fullEval x = idKey (v_name var) `seq` x
1690
1691    -- In safemode, we filter all prims marked as "unsafe".
1692    var | isAlpha (head sym)
1693        , fixity == "prefix"
1694        = cast ("&*" ++ sym)
1695        | otherwise
1696        = cast ("&*" ++ fixity ++ (':':sym))
1697
1698    pkg = do
1699        (_, pre) <- breakOnGlue "::" (reverse sym)
1700        return $ dropWhile (not . isAlphaNum) (reverse pre)
1701
1702    sub safe = codeRef $! mkPrim
1703        { subName     = cast sym
1704        , subType     = case pkg of
1705            Nothing | isMacro       -> SubMacro
1706                    | otherwise     -> SubPrim
1707            Just "Pugs::Internals"  -> SubPrim
1708            _                       -> SubMethod
1709        , subAssoc    = case assoc of
1710            "left"  -> A_left
1711            "right" -> A_right
1712            "non"   -> A_non
1713            "chain" -> A_chain
1714            "list"  -> A_list
1715            "spre"  -> AIrrelevantToParsing -- XXX HACK
1716            _       -> ANil
1717        , subParams   = prms
1718        , subReturns  = mkType ret
1719        , subBody     = Prim $! if safe then f else unsafe
1720        }
1721    unsafe :: [Val] -> Eval Val
1722    unsafe _ = fail $ "Unsafe function '" ++ sym ++ "' called under safe mode"
1723    f :: [Val] -> Eval Val
1724    f    = case arity of
1725        Arity0 -> op0 sym
1726        Arity1 -> \x -> case x of
1727            [a]       -> op1 symName a
1728            [a,b]     -> op2 sym a b
1729            [a,b,c]   -> op3 sym a b c
1730            [a,b,c,d] -> op4 sym a b c d
1731            a         -> op0 sym a
1732        Arity2 -> \[x,y] -> op2 sym x y
1733    symName = if modify then assoc ++ ":" ++ sym else sym
1734    -- prefix symName with post, circum or other (not yet used)
1735    -- to disambiguate, for example, &*prefix:++ and &*postfix:++ in 'op0'
1736    (arity, fixity, modify) = case assoc of
1737        "pre"       -> (Arity1, "prefix", False)
1738        "spre"      -> (Arity1, "prefix", False)
1739        "post"      -> (Arity1, "postfix", True)
1740        "circum"    -> (Arity1, "circumfix", True)
1741        "left"      -> (Arity2, "infix", False)
1742        "right"     -> (Arity2, "infix", False)
1743        "non"       -> (Arity2, "infix", False)
1744        "chain"     -> (Arity2, "infix", False)
1745        "list"      -> (Arity0, "infix", False)
1746        other       -> (Arity0, other, True)
1747
1748data Arity = Arity0 | Arity1 | Arity2
1749    deriving (Show, Eq, Ord, Typeable)
1750
1751-- |Produce a Pad update transaction with 'primOp' from a string description
1752primDecl :: String -> STM PadMutator
1753primDecl str = length str `seq` rv `seq` rv
1754    where
1755    rv = primOp sym assoc params ret
1756        ("safe" `isPrefixOf` traits)
1757        ("macro" `isSuffixOf` traits)
1758        ("export" `isSuffixOf` traits)
1759    (ret:assoc:sym:traits:prms) = words str
1760    takeWord = takeWord' . dropWhile (not . isWord)
1761    takeWord' "" = ""
1762    takeWord' (':':':':xs) = (':':':':takeWord' xs)
1763    takeWord' (x:xs) | isWord x = (x:takeWord' xs)
1764    takeWord' _ = ""
1765    isWord = not . (`elem` "(),:")
1766    prms'  = map takeWord prms
1767    prms'' = foldr foldParam [] prms'
1768    params = map (\p -> p{ isWritable = isLValue p }) prms''
1769
1770setFinalization :: Val -> Eval Val
1771setFinalization obj = do
1772    env <- ask
1773    -- XXX - Not sure if this can break guarantees in STM or not; disable for now
1774    if envAtomic env
1775        then return obj -- stm $ unsafeIOToSTM (obj `setFinalization` env)
1776        else io $ obj `setFinalizationIn` env
1777    where
1778    setFinalizationIn obj env = do
1779        objRef <- mkWeakPtr obj . Just $ do
1780            runEvalIO env $ do
1781                evalExp $ App (_Var "&DESTROYALL") (Just $ Val obj) []
1782            return ()
1783        modifyIORef _GlobalFinalizer (>> finalize objRef)
1784        return obj
1785
1786-- A "box" to put our polymorphic printer in
1787newtype PrettyPrinter = MkPrettyPrinter { runPrinter :: forall a. Pretty a => a -> String }
1788
1789-- op1 "perl"
1790op1Pretty :: PrettyPrinter -> Val -> Eval Val
1791op1Pretty printer v = do
1792    recur   <- io (newTVarIO False)
1793    let ?seen    = IntSet.empty
1794        ?recur   = recur
1795        ?printer = printer
1796    rv      <- prettyVal v
1797    isRecur <- stm (readTVar recur)
1798    return $ VStr $ decodeUTF8 $ if isRecur then "$_ := " ++ rv else rv
1799
1800prettyVal :: (?seen :: IntSet.IntSet, ?recur :: TVar Bool, ?printer :: PrettyPrinter) => Val -> Eval VStr
1801prettyVal v@(VRef r) = do
1802    ptr <- io (stableAddressOf r)
1803    if IntSet.member ptr ?seen
1804        then do
1805            stm $ writeTVar ?recur True
1806            return "\\$_"
1807        else let ?seen = IntSet.insert ptr ?seen in doPrettyVal v
1808prettyVal v = doPrettyVal v
1809
1810doPrettyVal :: (?seen :: IntSet.IntSet, ?recur :: TVar Bool, ?printer :: PrettyPrinter) => Val -> Eval VStr
1811doPrettyVal v@(VRef r) = do
1812    v'  <- readRef r
1813    ifValTypeIsa v "Pair"
1814        (case v' of
1815            VList [ks, vs] -> do
1816                kStr <- prettyVal ks
1817                vStr <- prettyVal vs
1818                return $ "(" ++ kStr ++ " => " ++ vStr ++ ")"
1819            _ -> prettyVal v'
1820        )
1821        (do str <- prettyVal v'
1822            ifValTypeIsa v "Array"
1823                (return $ ('[':(init (tail str))) ++ "]")
1824                (ifValTypeIsa v "Hash"
1825                    (return $ ('{':(init (tail str))) ++ "}")
1826                    (return ('\\':str)))
1827        )
1828doPrettyVal (VList vs) = do
1829    vs' <- mapM prettyVal vs
1830    -- (3,) should dump as (3,), not a (3), which would be the same as 3.
1831    return $ case vs' of
1832        []  -> "()"
1833        [x] -> "(" ++ x ++ ",)"
1834        _   -> "(" ++ concat (intersperse ", " vs') ++ ")"
1835doPrettyVal v@(VObject obj) = do
1836    -- ... dump the objAttrs
1837    -- XXX this needs fixing WRT demagicalized pairs:
1838    -- currently, this'll return Foo.new((attr => "value)), with the inner
1839    -- parens, which is, of course, wrong.
1840    hash    <- fromVal v :: Eval VHash
1841    str     <- prettyVal (VRef (hashRef hash))
1842    return $ showType (objType obj)
1843        ++ ".new(" ++ init (tail str) ++ ")"
1844doPrettyVal v = return (runPrinter ?printer v)
1845
1846-- XXX -- Junctive Types -- XXX --
1847
1848-- spre is "symbolic pre", that is, operators for which a precedence has
1849-- already been assigned in Parser.hs
1850
1851-- |Initial set global symbols to populate the evaluation environment
1852--  in the form of Pad mutating transactions built with 'primDecl'.
1853--
1854--  The source string format is:
1855--
1856-- >  ret_val   assoc   op_name [safe|unsafe] args
1857initSyms :: STM [PadMutator]
1858initSyms = seq (length syms) $ do
1859    rv <- mapM primDecl syms
1860    length rv `seq` return (length rv `seq` rv)
1861    where
1862    syms = filter (not . null) . lines $ "\
1863\\n   Bool      spre    !       safe   (Bool)\
1864\\n   Num       spre    +       safe   (Num)\
1865\\n   Num       pre     abs     safe   (Num)\
1866\\n   Int       pre     Pugs::Internals::truncate safe   (Num)\
1867\\n   Int       pre     Pugs::Internals::round    safe   (Num)\
1868\\n   Int       pre     Pugs::Internals::floor    safe   (Num)\
1869\\n   Int       pre     Pugs::Internals::ceiling  safe   (Num)\
1870\\n   Num       pre     atan    safe   (Num)\
1871\\n   Num       pre     atan    safe   (Num, Num)\
1872\\n   Num       pre     cos     safe   (Num)\
1873\\n   Num       pre     sin     safe   (Num)\
1874\\n   Num       pre     tan     safe   (Num)\
1875\\n   Any       pre     Pugs::Internals::pi      safe   ()\
1876\\n   Any       pre     self    safe,macro   ()\
1877\\n   Bool      pre     nothing safe   ()\
1878\\n   Num       pre     exp     safe   (Num, ?Num)\
1879\\n   Num       pre     sqrt    safe   (Num)\
1880\\n   Num       spre    -       safe   (Num)\
1881\\n   Str       spre    ~       safe   (Str)\
1882\\n   Bool      spre    ?       safe   (Bool)\
1883\\n   Str       spre    =       unsafe (?IO)\
1884\\n   List      spre    =       unsafe (?IO)\
1885\\n   Str       pre     readline unsafe (?IO)\
1886\\n   List      pre     readline unsafe (?IO)\
1887\\n   Str       pre     getc     unsafe (?IO)\
1888\\n   Str       pre     Pugs::Safe::safe_getc      safe ()\
1889\\n   Str       pre     Pugs::Safe::safe_readline  safe ()\
1890\\n   Int       pre     int     safe   (Int)\
1891\\n   List      pre     list    safe   (List)\
1892\\n   Hash      pre     hash    safe   (List)\
1893\\n   List      pre     pair    safe   (List)\
1894\\n   Scalar    pre     item    safe   (Scalar)\
1895\\n   Str       pre     Scalar::reverse safe   (Scalar)\
1896\\n   Any       pre     List::reverse safe   (Array)\
1897\\n   Any       pre     reverse safe   (Scalar, List)\
1898\\n   Any       pre     reverse safe   ()\
1899\\n   List      pre     eager   safe   (List)\
1900\\n   Int       spre    +^      safe   (Int)\
1901\\n   Int       spre    ~^      safe   (Str)\
1902\\n   Bool      spre    ?^      safe   (Bool)\
1903\\n   Ref       spre    \\      safe   (rw!Any)\
1904\\n   List      spre    ^       safe   (Scalar)\
1905\\n   List      post    ...     safe   (Str)\
1906\\n   List      post    ...     safe   (Scalar)\
1907\\n   Any       pre     undef     safe   ()\
1908\\n   Any       pre     undefine  safe   (?rw!Any)\
1909\\n   Str       pre     chop    safe   (Str)\
1910\\n   Str       pre     Scalar::chomp   safe   (Scalar)\
1911\\n   Any       pre     chomp   safe   (Scalar, List)\
1912\\n   Any       pre     chomp   safe   ()\
1913\\n   Any       right   =       safe   (rw!Any, Any)\
1914\\n   Int       pre     index   safe   (Str, Str, ?Int=0)\
1915\\n   Int       pre     rindex  safe   (Str, Str, ?Int)\
1916\\n   Int       pre     substr  safe   (rw!Str, Int, ?Int, ?Str)\
1917\\n   Str       pre     lc      safe   (Str)\
1918\\n   Str       pre     quotemeta safe   (Str)\
1919\\n   Str       pre     lcfirst safe   (Str)\
1920\\n   Str       pre     uc      safe   (Str)\
1921\\n   Str       pre     ucfirst safe   (Str)\
1922\\n   Str       pre     capitalize safe   (Str)\
1923\\n   Str       pre     crypt   safe   (Str, Str)\
1924\\n   Str       post    ++      safe   (rw!Str)\
1925\\n   Str       post    --      safe   (rw!Str)\
1926\\n   Num       post    ++      safe   (rw!Num)\
1927\\n   Num       post    --      safe   (rw!Num)\
1928\\n   Complex   post    i       safe   (Num)\
1929\\n   Str       spre    ++      safe   (rw!Str)\
1930\\n   Str       spre    --      safe   (rw!Str)\
1931\\n   Num       spre    ++      safe   (rw!Num)\
1932\\n   Num       spre    --      safe   (rw!Num)\
1933\\n   Bool      pre     not     safe   (Bool)\
1934\\n   Bool      pre     true    safe   (Bool)\
1935\\n   List      spre    gather  safe   (Code)\
1936\\n   List      pre     map     safe   (Code, List)\
1937\\n   List      pre     grep    safe   (Code, List)\
1938\\n   Scalar    pre     first   safe   (Code, List)\
1939\\n   List      pre     sort    safe   (Code, List)\
1940\\n   List      pre     reduce  safe   (Code, List)\
1941\\n   List      pre     produce safe   (Code, List)\
1942\\n   List      pre     sort    safe   (Array)\
1943\\n   List      pre     map     safe   (Array: Code)\
1944\\n   List      pre     grep    safe   (Array: Code)\
1945\\n   Scalar    pre     first   safe   (Array: Code)\
1946\\n   List      pre     sort    safe   (Array: Code)\
1947\\n   List      pre     reduce  safe   (Array: Code)\
1948\\n   List      pre     produce safe   (Array: Code)\
1949\\n   Any       pre     splice  safe   (rw!Array, ?Int=0)\
1950\\n   Any       pre     splice  safe   (rw!Array, Int, Int)\
1951\\n   Any       pre     splice  safe   (rw!Array, Int, Int, List)\
1952\\n   Int       pre     push    safe   (rw!Array, List)\
1953\\n   Int       pre     unshift safe   (rw!Array, List)\
1954\\n   Scalar    pre     List::pop     safe   (rw!Array)\
1955\\n   Scalar    pre     List::shift   safe   (rw!Array)\
1956\\n   Scalar    pre     sum     safe   (List)\
1957\\n   Scalar    pre     min     safe   (List)\
1958\\n   Scalar    pre     max     safe   (List)\
1959\\n   List      pre     uniq    safe   (List)\
1960\\n   Str       pre     join    safe   (Array: Str)\
1961\\n   Str       pre     join    safe   (Str, List)\
1962\\n   Any       pre     join    safe   (Thread)\
1963\\n   Bool      pre     detach  safe   (Thread)\
1964\\n   List      pre     cat     safe   (List)\
1965\\n   List      pre     zip     safe   (List)\
1966\\n   List      pre     each    safe   (List)\
1967\\n   List      pre     roundrobin    safe   (List)\
1968\\n   List      pre     keys    safe   (rw!Hash)\
1969\\n   List      pre     values  safe   (rw!Hash)\
1970\\n   List      pre     List::kv      safe,export   (rw!Hash)\
1971\\n   List      pre     pairs   safe   (rw!Hash)\
1972\\n   List      pre     keys    safe   (rw!Array)\
1973\\n   List      pre     values  safe   (rw!Array)\
1974\\n   List      pre     List::kv      safe,export   (rw!Array)\
1975\\n   List      pre     pairs   safe   (rw!Array)\
1976\\n   Scalar    pre     delete  safe   (rw!Hash: List)\
1977\\n   Scalar    pre     delete  safe   (rw!Array: List)\
1978\\n   Bool      pre     exists  safe   (rw!Hash: Str)\
1979\\n   Bool      pre     exists  safe   (rw!Array: Int)\
1980\\n   Str       pre     perl    safe   (rw!Any|Junction)\
1981\\n   Str       pre     guts    safe   (rw!Any|Junction)\
1982\\n   Any       pre     try     safe   (Code)\
1983\\n   Any       pre     lazy    safe   (Code)\
1984\\n   Any       pre     contend safe   (Code)\
1985\\n   Void      pre     defer   safe   ()\
1986\\n   Any       pre     Pugs::Internals::eval_perl6    safe   (Str)\
1987\\n   Any       pre     evalfile     unsafe (Str)\
1988\\n   Any       pre     Pugs::Internals::eval_parrot  unsafe (Str)\
1989\\n   Any       pre     Pugs::Internals::eval_perl5   safe (Str)\
1990\\n   Any       pre     Pugs::Internals::eval_haskell unsafe (Str)\
1991\\n   Any       pre     Pugs::Internals::eval_p6y unsafe (Str)\
1992\\n   Any       pre     Pugs::Internals::evalfile_p6y unsafe (Str)\
1993\\n   Any       pre     Pugs::Internals::eval_yaml    safe   (Str)\
1994\\n   Any       pre     Pugs::Internals::emit_yaml    unsafe   (rw!Any)\
1995\\n   Str       pre     yaml    safe   (rw!Any|Junction)\
1996\\n   Any       pre     Pugs::Internals::require unsafe (Str)\
1997\\n   Any       pre     Pugs::Internals::use     unsafe (Str)\
1998\\n   Any       pre     require unsafe (Str)\
1999\\n   Any       pre     use     unsafe (Str)\
2000\\n   Any       pre     require_haskell unsafe (Str)\
2001\\n   Any       pre     require_parrot  unsafe (Str)\
2002\\n   Any       pre     require_perl5   unsafe (Str)\
2003\\n   Any       pre     require_java    unsafe (Str)\
2004\\n   Any       pre     last    safe   (?Int=1)\
2005\\n   Any       pre     next    safe   (?Int=1)\
2006\\n   Any       pre     redo    safe   (?Int=1)\
2007\\n   Any       pre     continue    safe   (?Int=1)\
2008\\n   Any       pre     break    safe   (?Int=1)\
2009\\n   Any       pre     exit    safe   (?Int=0)\
2010\\n   Any       pre     srand   safe   (?Num)\
2011\\n   Num       pre     rand    safe   (?Num=1)\
2012\\n   Bool      pre     defined safe   (Any)\
2013\\n   Str       pre     WHAT     safe   (rw!Any|Junction)\
2014\\n   Str       pre     isa     safe   (rw!Any|Junction, Str)\
2015\\n   Str       pre     does    safe   (rw!Any|Junction, Str)\
2016\\n   Num       pre     time    safe   ()\
2017\\n   List      pre     times   safe   ()\
2018\\n   List      pre     Pugs::Internals::localtime   safe   (Num)\
2019\\n   Str       pre     want    safe   ()\
2020\\n   Str       pre     File::Spec::cwd     unsafe ()\
2021\\n   Str       pre     File::Spec::tmpdir  unsafe ()\
2022\\n   Str       pre     IO::next   unsafe (IO)\
2023\\n   Bool      pre     IO::print   unsafe (IO)\
2024\\n   Bool      pre     IO::print   unsafe (IO: List)\
2025\\n   Bool      pre     print   safe ()\
2026\\n   Bool      pre     print   safe (List)\
2027\\n   Bool      pre     IO::printf   unsafe (IO: Str, List)\
2028\\n   Bool      pre     printf   safe (Str, List)\
2029\\n   Str       pre     Pugs::Internals::sprintf safe   (Str, Num|Rat|Int|Str)\
2030\\n   Bool      pre     IO::say unsafe (IO)\
2031\\n   Bool      pre     IO::say unsafe (IO: List)\
2032\\n   Bool      pre     say     safe ()\
2033\\n   Bool      pre     say     safe (List)\
2034\\n   Bool      pre     Pugs::Safe::safe_print     safe     (Str)\
2035\\n   Bool      pre     flush   unsafe (IO)\
2036\\n   Bool      pre     IO::close   unsafe,export (IO:)\
2037\\n   Bool      pre     Socket::close   unsafe,export (Socket:)\
2038\\n   Bool      pre     die     safe   (?Object)\
2039\\n   Bool      pre     warn    safe   (List)\
2040\\n   Bool      pre     fail_   safe   (?Object)\
2041\\n   Bool      pre     fail    safe   (?Object)\
2042\\n   Socket    pre     listen  unsafe (Int)\
2043\\n   Socket    pre     connect unsafe (Str, Int)\
2044\\n   Any       pre     accept  unsafe (Any)\
2045\\n   List      pre     slurp   unsafe (Str)\
2046\\n   List      pre     slurp   unsafe (Handle)\
2047\\n   List      pre     readdir unsafe (Str)\
2048\\n   Bool      pre     Pugs::Internals::exec    unsafe (Str, Bool, List)\
2049\\n   Int       pre     run  unsafe (Str)\
2050\\n   Int       pre     run  unsafe (Str: List)\
2051\\n   Bool      pre     binmode unsafe (IO: ?Int=1)\
2052\\n   Void      pre     return  safe   ()\
2053\\n   Void      pre     return  safe   (rw!Any)\
2054\\n   Void      pre     return  safe   (List)\
2055\\n   Void      pre     leave   safe   ()\
2056\\n   Void      pre     leave   safe   (rw!Any)\
2057\\n   Void      pre     leave   safe   (List)\
2058\\n   Void      pre     yield   safe   ()\
2059\\n   Void      pre     yield   safe   (rw!Any)\
2060\\n   Void      pre     yield   safe   (List)\
2061\\n   Void      pre     take    safe   ()\
2062\\n   Void      pre     take    safe   (rw!Any)\
2063\\n   Void      pre     take    safe   (List)\
2064\\n   Junction  pre     any     safe   (List)\
2065\\n   Junction  pre     all     safe   (List)\
2066\\n   Junction  pre     one     safe   (List)\
2067\\n   Junction  pre     none    safe   (List)\
2068\\n   Bool      pre     sleep   unsafe (Int)\
2069\\n   Bool      pre     rmdir   unsafe (Str)\
2070\\n   Bool      pre     mkdir   unsafe (Str)\
2071\\n   Bool      pre     chdir   unsafe (Str)\
2072\\n   Int       pre     List::elems   safe,export   (rw!Array)\
2073\\n   Int       pre     List::end     safe,export   (Array)\
2074\\n   Int       pre     graphs  safe   (Str)\
2075\\n   Int       pre     codes   safe   (Str)\
2076\\n   Int       pre     chars   safe   (Str)\
2077\\n   Int       pre     bytes   safe   (Str)\
2078\\n   Int       pre     chmod   unsafe (Int, List)\
2079\\n   Scalar    pre     Pair::key     safe (rw!Pair)\
2080\\n   Scalar    pre     Pair::value   safe (rw!Pair)\
2081\\n   List      pre     keys    safe   (rw!Pair)\
2082\\n   List      pre     values  safe   (Pair|Junction)\
2083\\n   List      pre     Pair::kv      safe,export   (rw!Pair)\
2084\\n   List      pre     pairs   safe   (rw!Pair)\
2085\\n   Any       pre     pick    safe   (Any|Junction)\
2086\\n   List      pre     pick    safe   (Any|Junction: Int)\
2087\\n   Bool      pre     rename  unsafe (Str, Str)\
2088\\n   Bool      pre     symlink unsafe (Str, Str)\
2089\\n   Bool      pre     link    unsafe (Str, Str)\
2090\\n   Int       pre     unlink  unsafe (List)\
2091\\n   Str       pre     readlink unsafe (Str)\
2092\\n   List      pre     Str::split   safe   (Str)\
2093\\n   List      pre     Str::split   safe   (Str: Str)\
2094\\n   List      pre     Str::split   safe   (Str: Regex)\
2095\\n   List      pre     Str::split   safe   (Str: Str, Int)\
2096\\n   List      pre     Str::split   safe   (Str: Regex, Int)\
2097\\n   List      pre     split   safe   (Str, Str)\
2098\\n   List      pre     split   safe   (Str, Str, Int)\
2099\\n   List      pre     split   safe   (Regex, Str)\
2100\\n   List      pre     split   safe   (Regex, Str, Int)\
2101\\n   Str       spre    =       safe   (Any)\
2102\\n   List      spre    =       safe   (Any)\
2103\\n   Junction  list    |       safe   (Any|Junction)\
2104\\n   Junction  list    &       safe   (Any|Junction)\
2105\\n   Junction  list    ^       safe   (Any|Junction)\
2106\\n   Num       left    *       safe   (Num, Num)\
2107\\n   Num       left    /       safe   (Num, Num)\
2108\\n   Num       left    %       safe   (Num, Num)\
2109\\n   Str       left    x       safe   (Str, Int)\
2110\\n   List      left    xx      safe   (Any, Int)\
2111\\n   Int       left    +&      safe   (Int, Int)\
2112\\n   Int       left    +<      safe   (Int, Int)\
2113\\n   Int       left    +>      safe   (Int, Int)\
2114\\n   Str       left    ~&      safe   (Str, Str)\
2115\\n   Str       left    ~<      safe   (Str, Str)\
2116\\n   Str       left    ~>      safe   (Str, Str)\
2117\\n   Num       right   **      safe   (Num, Num)\
2118\\n   Num       left    +       safe   (Num, Num)\
2119\\n   Num       left    -       safe   (Num, Num)\
2120\\n   Str       left    ~       safe   (Str, Str)\
2121\\n   Int       left    +|      safe   (Int, Int)\
2122\\n   Int       left    +^      safe   (Int, Int)\
2123\\n   Str       left    ~|      safe   (Str, Str)\
2124\\n   Str       left    ~^      safe   (Str, Str)\
2125\\n   Bool      left    ?|      safe   (Bool, Bool)\
2126\\n   Bool      left    ?^      safe   (Bool, Bool)\
2127\\n   Bool      left    ?&      safe   (Bool, Bool)\
2128\\n   Pair      right   =>      safe   (Any, Any)\
2129\\n   Int       non     cmp     safe   (Any, Any)\
2130\\n   Int       non     leg     safe   (Str, Str)\
2131\\n   Int       non     <=>     safe   (Num, Num)\
2132\\n   List      non     ..      safe   (Scalar, Scalar)\
2133\\n   List      non     ..^     safe   (Scalar, Scalar)\
2134\\n   List      non     ^..     safe   (Scalar, Scalar)\
2135\\n   List      non     ^..^    safe   (Scalar, Scalar)\
2136\\n   Bool      chain   !=      safe   (Num, Num)\
2137\\n   Bool      chain   ==      safe   (Num, Num)\
2138\\n   Bool      chain   =:=     safe   (rw!Any, rw!Any)\
2139\\n   Bool      chain   ===     safe   (Any, Any)\
2140\\n   Bool      chain   eqv     safe   (Any, Any)\
2141\\n   Bool      chain   ~~      safe   (rw!Any, Any)\
2142\\n   Bool      chain   <       safe   (Num, Num)\
2143\\n   Bool      chain   <=      safe   (Num, Num)\
2144\\n   Bool      chain   >       safe   (Num, Num)\
2145\\n   Bool      chain   >=      safe   (Num, Num)\
2146\\n   Bool      chain   ne      safe   (Str, Str)\
2147\\n   Bool      chain   eq      safe   (Str, Str)\
2148\\n   Bool      chain   lt      safe   (Str, Str)\
2149\\n   Bool      chain   le      safe   (Str, Str)\
2150\\n   Bool      chain   gt      safe   (Str, Str)\
2151\\n   Bool      chain   ge      safe   (Str, Str)\
2152\\n   Scalar    left    &&      safe   (Bool, ~Bool)\
2153\\n   Scalar    left    ||      safe   (Bool, ~Bool)\
2154\\n   Scalar    left    ^^      safe   (Bool, Bool)\
2155\\n   Scalar    left    //      safe   (Bool, ~Bool)\
2156\\n   Scalar    left    .[]     safe   (Array, Int)\
2157\\n   Scalar    left    .{}     safe   (Hash, Str)\
2158\\n   List      list    Z       safe   (Array)\
2159\\n   List      list    X       safe   (Array)\
2160\\n   List      spre    <==     safe   (List)\
2161\\n   List      left    ==>     safe   (List, Code)\
2162\\n   Scalar    left    and     safe   (Bool, ~Bool)\
2163\\n   Scalar    left    or      safe   (Bool, ~Bool)\
2164\\n   Scalar    left    xor     safe   (Bool, Bool)\
2165\\n   Scalar    left    orelse  safe   (Bool, ~Bool)\
2166\\n   Scalar    left    andthen safe   (Bool, ~Bool)\
2167\\n   Str       pre     chr     safe   (Int)\
2168\\n   Int       pre     ord     safe   (Str)\
2169\\n   Str       pre     oct     safe   (Str)\
2170\\n   Object    pre     stat    unsafe  (Str)\
2171\\n   Object    pre     lstat   unsafe  (Str)\
2172\\n   Int       pre     from    safe   (Match)\
2173\\n   Int       pre     to      safe   (Match)\
2174\\n   List      pre     matches safe   (Match)\
2175\\n   Str       pre     oct     safe   (Int)\
2176\\n   Num       pre     log     safe   (Int)\
2177\\n   Num       pre     log     safe   (Num)\
2178\\n   Num       pre     log10   safe   (Num)\
2179\\n   Thread    pre     async   safe   (Code)\
2180\\n   Thread    pre     fork    unsafe ()\
2181\\n   Int       pre     sign    safe   (Num)\
2182\\n   Bool      pre     kill    safe   (Thread)\
2183\\n   Int       pre     kill    unsafe (Int, List)\
2184\\n   Object    pre     Object::new     safe,export   (Object: Named)\
2185\\n   Object    pre     BUILDALL   safe   (Object)\
2186\\n   Object    pre     DESTROYALL safe   (Object)\
2187\\n   Code      pre     TEMP    safe   (rw!Any)\
2188\\n   Object    pre     Object::clone   safe   (Object: Named)\
2189\\n   Class     pre     Object::HOW    safe,export   (Object)\
2190\\n   Object    pre     HOW::new     safe   (Object: Named)\
2191\\n   Object    pre     HOW::does     safe   (Object: List)\
2192\\n   Str       pre     Class::name    safe   (Class)\
2193\\n   Hash      pre     Class::traits  safe   (Class)\
2194\\n   Object    pre     WHICH      safe   (Any)\
2195\\n   Int       pre     Rat::numerator   safe   (Rat:)\
2196\\n   Int       pre     Rat::denominator safe   (Rat:)\
2197\\n   Bool      pre     Thread::yield   safe   (Thread)\
2198\\n   List      pre     Pugs::Internals::runShellCommand        unsafe (Str)\
2199\\n   List      pre     Pugs::Internals::runInteractiveCommand  unsafe (Str)\
2200\\n   Bool      pre     Pugs::Internals::hSetBinaryMode         unsafe (IO, Str)\
2201\\n   Void      pre     Pugs::Internals::hSeek                  unsafe (IO, Int, Int)\
2202\\n   Int       pre     IO::tell                                unsafe,export (IO)\
2203\\n   Bool      pre     Pugs::Internals::hIsOpen                unsafe (IO)\
2204\\n   Bool      pre     Pugs::Internals::hIsClosed              unsafe (IO)\
2205\\n   Bool      pre     Pugs::Internals::hIsReadable            unsafe (IO)\
2206\\n   Bool      pre     Pugs::Internals::hIsWritable            unsafe (IO)\
2207\\n   Bool      pre     Pugs::Internals::hIsSeekable            unsafe (IO)\
2208\\n   IO        pre     Pugs::Internals::openFile               unsafe (Str, Str)\
2209\\n   List      pre     Pugs::Internals::caller                 safe (Any, Int, Str)\
2210\\n   Any       pre     Pugs::Internals::check_for_io_leak      safe (Code)\
2211\\n   Bool      pre     Bool::True  safe   ()\
2212\\n   Bool      pre     Bool::False safe   ()\
2213\\n   Bool      pre     True  safe,macro   ()\
2214\\n   Bool      pre     False safe,macro   ()\
2215\\n   List      spre    prefix:[,]  safe   (List)\
2216\\n   List      spre    prefix:@<<    safe   (List)\
2217\\n   List      spre    prefix:$<<    safe   (List)\
2218\\n   List      spre    prefix:&<<    safe   (List)\
2219\\n   List      spre    prefix:%<<    safe   (List)\
2220\\n   Str       pre     Code::name    safe   (Code:)\
2221\\n   Int       pre     Code::arity   safe   (Code:)\
2222\\n   Str       pre     Code::assoc   safe   (Code:)\
2223\\n   Code::Exp pre     Code::body    safe   (Code:)\
2224\\n   Str       pre     Code::pos     safe   (Code:)\
2225\\n   Any       pre     Code::signature     safe   (Code:)\
2226\\n   IO::Dir   pre     opendir    unsafe (Str)\
2227\\n   Str       pre     IO::Dir::read       unsafe,export (IO::Dir:)\
2228\\n   List      pre     IO::Dir::read       unsafe,export (IO::Dir:)\
2229\\n   Str       pre     IO::Dir::readdir    unsafe,export (IO::Dir:)\
2230\\n   List      pre     IO::Dir::readdir    unsafe,export (IO::Dir:)\
2231\\n   Bool      pre     IO::Dir::close      unsafe,export (IO::Dir:)\
2232\\n   Bool      pre     IO::Dir::closedir   unsafe,export (IO::Dir:)\
2233\\n   Bool      pre     IO::Dir::rewind     unsafe,export (IO::Dir:)\
2234\\n   Bool      pre     IO::Dir::rewinddir  unsafe,export (IO::Dir:)\
2235\\n   Any       pre     Pugs::Internals::reduceVar  unsafe (Str)\
2236\\n   Str       pre     Pugs::Internals::rule_pattern safe (Regex)\
2237\\n   Hash      pre     Pugs::Internals::rule_adverbs safe (Regex)\
2238\\n   Int       pre     Pugs::Internals::install_pragma_value safe (Str, Int)\
2239\\n   Bool      pre     Pugs::Internals::current_pragma_value safe (Str)\
2240\\n   Bool      pre     Pugs::Internals::caller_pragma_value safe (Str)\
2241\\n   Num       pre     Pugs::Internals::base      safe (Int, Any)\
2242\\n   Any       pre     vv      safe (Any)\
2243\\n"
Note: See TracBrowser for help on using the browser.