| 1 | {-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-} |
|---|
| 2 | |
|---|
| 3 | module Pugs.Prim.Yaml ( evalYaml, dumpYaml, stableAddressOf ) where |
|---|
| 4 | import Pugs.Internals |
|---|
| 5 | import Pugs.AST |
|---|
| 6 | import Pugs.Pretty |
|---|
| 7 | import Pugs.Types |
|---|
| 8 | import Data.Yaml.Syck |
|---|
| 9 | import Foreign.StablePtr |
|---|
| 10 | import Foreign.Ptr |
|---|
| 11 | import qualified Data.Map as Map |
|---|
| 12 | import qualified Data.IntSet as IntSet |
|---|
| 13 | import qualified Data.ByteString as Str |
|---|
| 14 | import qualified Data.HashTable as H |
|---|
| 15 | import DrIFT.YAML |
|---|
| 16 | |
|---|
| 17 | evalYaml :: Val -> Eval Val |
|---|
| 18 | evalYaml cv = do |
|---|
| 19 | str <- fromVal cv |
|---|
| 20 | node <- guardIO (parseYaml $ encodeUTF8 str) |
|---|
| 21 | fromYaml node |
|---|
| 22 | |
|---|
| 23 | fromYaml :: YamlNode -> Eval Val |
|---|
| 24 | fromYaml MkNode{n_elem=ENil} = return VUndef |
|---|
| 25 | fromYaml MkNode{n_elem=EStr str} = return $ VStr $ decodeUTF8 $ unpackBuf str |
|---|
| 26 | fromYaml MkNode{n_elem=ESeq nodes} = do |
|---|
| 27 | av <- mapM fromYaml nodes |
|---|
| 28 | val <- newArray av |
|---|
| 29 | return (VRef $ MkRef val) |
|---|
| 30 | fromYaml MkNode{n_elem=EMap nodes, n_tag=tag} = do |
|---|
| 31 | case tag of |
|---|
| 32 | Nothing -> do |
|---|
| 33 | vals <- forM nodes $ \(keyNode, valNode) -> do |
|---|
| 34 | key <- fromVal =<< fromYaml keyNode |
|---|
| 35 | val <- newScalar =<< fromYaml valNode |
|---|
| 36 | return (key, val) |
|---|
| 37 | hv <- io $ (H.fromList H.hashString vals :: IO IHash) |
|---|
| 38 | return $ VRef (hashRef hv) |
|---|
| 39 | Just s | (pre, post) <- Str.splitAt 16 s -- 16 == length "tag:pugs:Object:" |
|---|
| 40 | , pre == packBuf "tag:pugs:Object:" -> do |
|---|
| 41 | let typ = unpackBuf post |
|---|
| 42 | vals <- forM nodes $ \(keyNode, valNode) -> do |
|---|
| 43 | key <- fromVal =<< fromYaml keyNode |
|---|
| 44 | val <- fromYaml valNode |
|---|
| 45 | return (key, val) |
|---|
| 46 | return . VObject =<< createObject (mkType typ) vals |
|---|
| 47 | Just s | s == packBuf "tag:pugs:Rule" -> do |
|---|
| 48 | vals <- forM nodes $ \(keyNode, valNode) -> do |
|---|
| 49 | key <- fromVal =<< fromYaml keyNode |
|---|
| 50 | val <- fromYaml valNode |
|---|
| 51 | return (key, val) |
|---|
| 52 | --let spec = Map.fromList (vals :: [(String, Val)]) |
|---|
| 53 | --spec <- io . newTVarIO . Map.map lazyScalar $ Map.fromList (vals :: [(String, Val)]) |
|---|
| 54 | spec' <- io . newTVarIO $ Map.fromList (vals :: [(String, Val)]) |
|---|
| 55 | spec <- stm . readTVar $ spec' |
|---|
| 56 | rule <- fromVal =<< Map.lookup "rule" spec |
|---|
| 57 | global <- fromVal =<< Map.lookup "global" spec |
|---|
| 58 | stringify <- fromVal =<< Map.lookup "stringify" spec |
|---|
| 59 | adverbs <- Map.lookup "adverbs" spec |
|---|
| 60 | return $ VRule MkRulePGE{rxRule=rule, rxGlobal=global, rxStringify=stringify, rxAdverbs=adverbs} |
|---|
| 61 | Just x -> error ("can't deserialize: " ++ unpackBuf x) |
|---|
| 62 | |
|---|
| 63 | dumpYaml :: Val -> Eval Val |
|---|
| 64 | dumpYaml v = do |
|---|
| 65 | let ?seen = IntSet.empty |
|---|
| 66 | obj <- toYaml v |
|---|
| 67 | rv <- guardIO . emitYaml $ obj |
|---|
| 68 | (return . VStr . decodeUTF8) rv |
|---|
| 69 | |
|---|
| 70 | strNode :: String -> YamlNode |
|---|
| 71 | strNode = mkNode . EStr . packBuf |
|---|
| 72 | |
|---|
| 73 | stableAddressOf :: a -> IO Int |
|---|
| 74 | stableAddressOf x = do |
|---|
| 75 | ptr <- newStablePtr x |
|---|
| 76 | return (castStablePtrToPtr ptr `minusPtr` (nullPtr :: Ptr ())) |
|---|
| 77 | |
|---|
| 78 | toYaml :: (?seen :: IntSet.IntSet) => Val -> Eval YamlNode |
|---|
| 79 | toYaml VUndef = return $ mkNode ENil |
|---|
| 80 | toYaml (VBool x) = return $ boolToYaml x |
|---|
| 81 | toYaml (VStr str) = return $ strNode (encodeUTF8 str) |
|---|
| 82 | toYaml v@(VRef r) = do |
|---|
| 83 | ptr <- io $ stableAddressOf r |
|---|
| 84 | if IntSet.member ptr ?seen then return nilNode{ n_anchor = AReference ptr } else do |
|---|
| 85 | let ?seen = IntSet.insert ptr ?seen |
|---|
| 86 | node <- ifValTypeIsa v "Hash" (hashToYaml r) $ do |
|---|
| 87 | v' <- readRef r |
|---|
| 88 | nodes <- toYaml v' |
|---|
| 89 | ifValTypeIsa v "Array" (return nodes) $ case v' of |
|---|
| 90 | VObject _ -> return nodes |
|---|
| 91 | _ -> io $ toYamlNode r |
|---|
| 92 | return node{ n_anchor = AAnchor ptr } |
|---|
| 93 | toYaml (VList nodes) = do |
|---|
| 94 | n <- mapM toYaml nodes |
|---|
| 95 | return $ mkNode (ESeq n) |
|---|
| 96 | -- fmap ESeq$ mapM toYaml nodes |
|---|
| 97 | toYaml v@(VObject obj) = do |
|---|
| 98 | -- ... dump the objAttrs |
|---|
| 99 | -- XXX this needs fixing WRT demagicalized pairs: |
|---|
| 100 | -- currently, this'll return Foo.new((attr => "value)), with the inner |
|---|
| 101 | -- parens, which is, of course, wrong. |
|---|
| 102 | hash <- fromVal v :: Eval VHash |
|---|
| 103 | attrs <- toYaml $ VRef (hashRef hash) |
|---|
| 104 | return $ tagNode (Just $ packBuf $ "tag:pugs:Object:" ++ showType (objType obj)) attrs |
|---|
| 105 | toYaml (VRule MkRulePGE{rxRule=rule, rxGlobal=global, rxStringify=stringify, rxAdverbs=adverbs}) = do |
|---|
| 106 | adverbs' <- toYaml adverbs |
|---|
| 107 | return . mkTagNode "tag:pugs:Rule" $ EMap |
|---|
| 108 | [ (strNode "rule", strNode rule) |
|---|
| 109 | , (strNode "global", boolToYaml global) |
|---|
| 110 | , (strNode "stringify", boolToYaml stringify) |
|---|
| 111 | , (strNode "adverbs", adverbs') |
|---|
| 112 | ] |
|---|
| 113 | toYaml v = return $ strNode $ (encodeUTF8 . pretty) v |
|---|
| 114 | |
|---|
| 115 | hashToYaml :: (?seen :: IntSet.IntSet) => VRef -> Eval YamlNode |
|---|
| 116 | hashToYaml (MkRef (IHash hv)) = do |
|---|
| 117 | h <- hash_fetch hv |
|---|
| 118 | let assocs = Map.toList h |
|---|
| 119 | yamlmap <- forM assocs $ \(ka, va) -> do |
|---|
| 120 | ka' <- toYaml $ VStr ka |
|---|
| 121 | va' <- toYaml va |
|---|
| 122 | return (ka', va') |
|---|
| 123 | return $ mkNode (EMap yamlmap) |
|---|
| 124 | hashToYaml r = error ("unexpected node: " ++ show r) |
|---|
| 125 | |
|---|
| 126 | boolToYaml :: VBool -> YamlNode |
|---|
| 127 | boolToYaml True = strNode "true" |
|---|
| 128 | boolToYaml False = strNode "false" |
|---|