| 1 | {-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-} |
|---|
| 2 | |
|---|
| 3 | module Pugs.Prim.Keyed ( |
|---|
| 4 | -- keyed values (Val) |
|---|
| 5 | pairsFromVal, keysFromVal, valuesFromVal, |
|---|
| 6 | |
|---|
| 7 | -- keyed references (VRef) |
|---|
| 8 | pairsFromRef, keysFromRef, valuesFromRef, |
|---|
| 9 | existsFromRef, deleteFromRef, |
|---|
| 10 | ) where |
|---|
| 11 | import Pugs.Internals |
|---|
| 12 | import Pugs.AST |
|---|
| 13 | import Pugs.Types |
|---|
| 14 | import qualified Data.Map as Map |
|---|
| 15 | import qualified Data.Set as Set |
|---|
| 16 | |
|---|
| 17 | pairsFromVal :: Val -> Eval [Val] |
|---|
| 18 | pairsFromVal VUndef = return [] |
|---|
| 19 | pairsFromVal (PerlSV sv) = do |
|---|
| 20 | keys <- hash_fetchKeys sv |
|---|
| 21 | return $ VList (map castV keys) |
|---|
| 22 | elems <- mapM (hash_fetchElem sv) keys |
|---|
| 23 | return $ map (VRef . MkRef . IPair) (keys `zip` elems) |
|---|
| 24 | pairsFromVal (VRef ref) = pairsFromRef ref |
|---|
| 25 | pairsFromVal v = fallback pairsFromVal v |
|---|
| 26 | |
|---|
| 27 | fallback :: (Val -> Eval b) -> Val -> Eval b |
|---|
| 28 | fallback f v@(VV vv) = do |
|---|
| 29 | val <- vvToVal vv |
|---|
| 30 | case val of |
|---|
| 31 | VV{} -> die "Not a keyed object" v |
|---|
| 32 | _ -> f val |
|---|
| 33 | fallback _ v = die "Not a keyed value" v |
|---|
| 34 | |
|---|
| 35 | keysFromVal :: Val -> Eval Val |
|---|
| 36 | keysFromVal VUndef = return $ VList [] |
|---|
| 37 | keysFromVal (PerlSV sv) = do |
|---|
| 38 | keys <- hash_fetchKeys sv |
|---|
| 39 | return $ VList (map castV keys) |
|---|
| 40 | keysFromVal (VList vs) = return . VList $ map VInt [0 .. (genericLength vs) - 1] |
|---|
| 41 | keysFromVal (VRef ref) = do |
|---|
| 42 | vals <- keysFromRef ref |
|---|
| 43 | return $ VList vals |
|---|
| 44 | keysFromVal v = fallback keysFromVal v |
|---|
| 45 | |
|---|
| 46 | valuesFromVal :: Val -> Eval Val |
|---|
| 47 | valuesFromVal VUndef = return $ VList [] |
|---|
| 48 | valuesFromVal (VJunc j) = return . VList . Set.elems $ juncSet j |
|---|
| 49 | valuesFromVal v@(VList _) = return v |
|---|
| 50 | valuesFromVal (VRef ref) = do |
|---|
| 51 | vals <- valuesFromRef ref |
|---|
| 52 | return $ VList vals |
|---|
| 53 | valuesFromVal (PerlSV sv) = do |
|---|
| 54 | pairs <- hash_fetch sv |
|---|
| 55 | return . VList $ Map.elems pairs |
|---|
| 56 | valuesFromVal v = fallback valuesFromVal v |
|---|
| 57 | |
|---|
| 58 | -- XXX These bulks of code below screams for refactoring |
|---|
| 59 | |
|---|
| 60 | pairsFromRef :: VRef -> Eval [Val] |
|---|
| 61 | pairsFromRef r@(MkRef (IPair _)) = do |
|---|
| 62 | return [VRef r] |
|---|
| 63 | pairsFromRef (MkRef (IHash hv)) = do |
|---|
| 64 | keys <- hash_fetchKeys hv |
|---|
| 65 | elems <- mapM (hash_fetchElem hv) keys |
|---|
| 66 | return $ map (VRef . MkRef . IPair) (keys `zip` elems) |
|---|
| 67 | pairsFromRef (MkRef (IArray av)) = do |
|---|
| 68 | vals <- array_fetch av |
|---|
| 69 | return $ map castV ((map VInt [0..]) `zip` vals) |
|---|
| 70 | pairsFromRef (MkRef (IScalar sv)) = do |
|---|
| 71 | refVal <- scalar_fetch' sv |
|---|
| 72 | pairsFromVal refVal |
|---|
| 73 | pairsFromRef ref = die "Not a keyed reference" ref |
|---|
| 74 | |
|---|
| 75 | keysFromRef :: VRef -> Eval [Val] |
|---|
| 76 | keysFromRef (MkRef (IPair pv)) = do |
|---|
| 77 | key <- pair_fetchKey pv |
|---|
| 78 | return [key] |
|---|
| 79 | keysFromRef (MkRef (IHash hv)) = do |
|---|
| 80 | keys <- hash_fetchKeys hv |
|---|
| 81 | return $ map castV keys |
|---|
| 82 | keysFromRef (MkRef (IArray av)) = do |
|---|
| 83 | keys <- array_fetchKeys av |
|---|
| 84 | return $ map castV keys |
|---|
| 85 | keysFromRef (MkRef (IScalar sv)) = do |
|---|
| 86 | refVal <- scalar_fetch' sv |
|---|
| 87 | if defined refVal |
|---|
| 88 | then fromVal =<< keysFromVal refVal |
|---|
| 89 | else return [] |
|---|
| 90 | keysFromRef ref = die "Not a keyed reference" ref |
|---|
| 91 | |
|---|
| 92 | valuesFromRef :: VRef -> Eval [Val] |
|---|
| 93 | valuesFromRef (MkRef (IPair pv)) = do |
|---|
| 94 | val <- pair_fetchVal pv |
|---|
| 95 | return [val] |
|---|
| 96 | valuesFromRef (MkRef (IHash hv)) = do |
|---|
| 97 | pairs <- hash_fetch hv |
|---|
| 98 | return $ Map.elems pairs |
|---|
| 99 | valuesFromRef (MkRef (IArray av)) = array_fetch av |
|---|
| 100 | valuesFromRef (MkRef (IScalar sv)) = do |
|---|
| 101 | refVal <- scalar_fetch' sv |
|---|
| 102 | if defined refVal |
|---|
| 103 | then fromVal =<< valuesFromVal refVal |
|---|
| 104 | else return [] |
|---|
| 105 | valuesFromRef ref = die "Not a keyed reference" ref |
|---|
| 106 | |
|---|
| 107 | existsFromRef :: VRef -> Val -> Eval VBool |
|---|
| 108 | existsFromRef (MkRef (IHash hv)) val = do |
|---|
| 109 | idx <- fromVal val |
|---|
| 110 | hash_existsElem hv idx |
|---|
| 111 | existsFromRef (MkRef (IArray av)) val = do |
|---|
| 112 | idx <- fromVal val |
|---|
| 113 | array_existsElem av idx |
|---|
| 114 | existsFromRef (MkRef (IScalar sv)) val = do |
|---|
| 115 | refVal <- scalar_fetch' sv |
|---|
| 116 | case refVal of |
|---|
| 117 | VRef ref -> existsFromRef ref val |
|---|
| 118 | VList _ -> (`existsFromRef` val) =<< fromVal refVal |
|---|
| 119 | _ -> return False |
|---|
| 120 | existsFromRef ref _ = die "Not a keyed reference" ref |
|---|
| 121 | |
|---|
| 122 | deleteFromRef :: VRef -> Val -> Eval Val |
|---|
| 123 | deleteFromRef (MkRef (IHash hv)) val = do |
|---|
| 124 | idxs <- fromVals val |
|---|
| 125 | rv <- forM idxs $ \idx -> do |
|---|
| 126 | val <- hash_fetchVal hv idx |
|---|
| 127 | hash_deleteElem hv idx |
|---|
| 128 | return val |
|---|
| 129 | return $ VList rv |
|---|
| 130 | deleteFromRef (MkRef (IArray av)) val = do |
|---|
| 131 | idxs <- fromVals val |
|---|
| 132 | rv <- forM idxs $ \idx -> do |
|---|
| 133 | val <- array_fetchVal av idx |
|---|
| 134 | array_deleteElem av idx |
|---|
| 135 | return val |
|---|
| 136 | return $ VList rv |
|---|
| 137 | deleteFromRef (MkRef (IScalar sv)) val = do |
|---|
| 138 | refVal <- scalar_fetch' sv |
|---|
| 139 | case refVal of |
|---|
| 140 | VRef ref -> deleteFromRef ref val |
|---|
| 141 | VList _ -> (`deleteFromRef` val) =<< fromVal refVal |
|---|
| 142 | v -> die "Argument is not a Hash or Array element or slice in delete" v |
|---|
| 143 | deleteFromRef ref _ = die "Argument is not a Hash or Array element or slice in delete" ref |
|---|