root/src/Pugs/Prim/Yaml.hs

Revision 15777, 5.0 kB (checked in by audreyt, 19 months ago)

* Gain another ~10% on startup speed (Prelude+Test) by simply

changing all "atomically . newTVar" to "newTVarIO" when
atomicity is irrelevant.

  • 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 #-}
2
3module Pugs.Prim.Yaml ( evalYaml, dumpYaml, stableAddressOf ) where
4import Pugs.Internals
5import Pugs.AST
6import Pugs.Pretty
7import Pugs.Types
8import Data.Yaml.Syck
9import Foreign.StablePtr
10import Foreign.Ptr
11import qualified Data.Map as Map
12import qualified Data.IntSet as IntSet
13import qualified Data.ByteString as Str
14import qualified Data.HashTable as H
15import DrIFT.YAML
16
17evalYaml :: Val -> Eval Val
18evalYaml cv = do
19    str     <- fromVal cv
20    node    <- guardIO (parseYaml $ encodeUTF8 str)
21    fromYaml node
22
23fromYaml :: YamlNode -> Eval Val
24fromYaml MkNode{n_elem=ENil}       = return VUndef
25fromYaml MkNode{n_elem=EStr str}   = return $ VStr $ decodeUTF8 $ unpackBuf str
26fromYaml MkNode{n_elem=ESeq nodes} = do
27    av  <- mapM fromYaml nodes
28    val <- newArray av
29    return (VRef $ MkRef val)
30fromYaml 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
63dumpYaml :: Val -> Eval Val
64dumpYaml v = do
65    let ?seen = IntSet.empty
66    obj     <- toYaml v
67    rv      <- guardIO . emitYaml $ obj
68    (return . VStr . decodeUTF8) rv
69
70strNode :: String -> YamlNode
71strNode = mkNode . EStr . packBuf
72
73stableAddressOf :: a -> IO Int
74stableAddressOf x = do
75    ptr <- newStablePtr x
76    return (castStablePtrToPtr ptr `minusPtr` (nullPtr :: Ptr ()))
77
78toYaml :: (?seen :: IntSet.IntSet) => Val -> Eval YamlNode
79toYaml VUndef       = return $ mkNode ENil
80toYaml (VBool x)    = return $ boolToYaml x
81toYaml (VStr str)   = return $ strNode (encodeUTF8 str)
82toYaml 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 }
93toYaml (VList nodes) = do
94    n <- mapM toYaml nodes
95    return $ mkNode (ESeq n)
96    -- fmap ESeq$ mapM toYaml nodes
97toYaml 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
105toYaml (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        ]
113toYaml v = return $ strNode $ (encodeUTF8 . pretty) v
114
115hashToYaml :: (?seen :: IntSet.IntSet) => VRef -> Eval YamlNode
116hashToYaml (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)
124hashToYaml r = error ("unexpected node: " ++ show r)
125
126boolToYaml :: VBool -> YamlNode
127boolToYaml True  = strNode "true"
128boolToYaml False = strNode "false"
Note: See TracBrowser for help on using the browser.