root/src/Pugs/Class.hs

Revision 21673, 6.0 kB (checked in by audreyt, 2 months ago)

* Import Pugs 6.2.13.11 from Hackage into our source tree.
* Highlights:

  • Much faster startup time
  • Slightly faster compilation time (mostly due to refactored Pugs.AST.Internals)
  • Portable-to-Win32 readline thanks to Haskeline
  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
Line 
1{-# OPTIONS_GHC -fglasgow-exts -fparr -fallow-undecidable-instances -fallow-incoherent-instances #-}
2
3{-|
4    Class meta-model.  (object meta-meta-model)
5
6>   Learn now the lore of Living Creatures!
7>   First name the four, the free peoples:
8>   Eldest of all, the elf-children;
9>   Dwarf the delver, dark are his houses;
10>   Ent the earthborn, old as mountains;
11>   Man the mortal, master of horses...
12-}
13
14module Pugs.Class
15    ( module Pugs.Class
16    , module Pugs.AST.Eval
17    , module MO.Run
18    , module MO.Compile
19    , module MO.Compile.Class
20    , module MO.Util
21    , module Control.Monad.Fix
22    ) where
23import MO.Run hiding (__)
24import MO.Compile
25import MO.Compile.Class
26import MO.Util hiding (traceM, traceShow)
27import Pugs.Internals
28import Pugs.AST.Eval
29import Control.Monad.Fix
30import qualified StringTable.AtomMap as AtomMap
31import qualified Data.Typeable as Typeable
32
33type Val = Invocant Eval
34type Call = MethodInvocation Eval
35
36class (Show a, Typeable a, Ord a) => Boxable a where
37    mkVal :: a -> Val
38    mkVal x = MkInvocant x (class_interface (classOf x))
39
40    coerceVal :: Val -> Eval a
41    coerceVal (MkInvocant x _) = case Typeable.cast x of
42        Just y -> return y
43        _      -> fail $ "Cannot coerce from " ++ (show $ typeOf x) ++ " to " ++ (show $ typeOf (undefined :: a))
44
45    instanceMethods :: [(ID, MethodPrim a)]
46    instanceMethods = []
47
48    classOf :: a -> PureClass
49    classOf _ = mkPureClass (classNameOf (undefined :: a)) (instanceMethods :: [(ID, MethodPrim a)])
50
51    classNameOf :: a -> String
52    classNameOf _ = takeTypeName "" . reverse . show . typeOf $ (undefined :: a)
53        -- Here we intuit "Str" from "Pugs.Val.Str.PureStr".
54        where
55        takeTypeName acc [] = acc
56        takeTypeName acc (x:xs)
57            | isLower x = takeTypeName (x:acc) xs
58            | otherwise = x:acc
59
60type MethodPrim a = (a -> [:Val:] -> Eval Val)
61
62class Boxable b => MethodPrimable a b | a -> b where
63    asPrim :: a -> MethodPrim b
64
65instance Boxable a => MethodPrimable Val a where
66    asPrim v _ _ = return v
67
68instance Boxable a => MethodPrimable Call a where
69    asPrim f x _ = ivDispatch (mkVal x) f
70
71-- Auto-generate pure instances from Eval instances
72instance MethodPrimable (a -> b -> Eval z) a => MethodPrimable (a -> b -> z) a where
73    asPrim f = asPrim ((\x args -> return (f x args)) :: (a -> b -> Eval z))
74
75instance MethodPrimable (a -> b -> c -> Eval z) a => MethodPrimable (a -> b -> c -> z) a where
76    asPrim f = asPrim ((\x y args -> return (f x y args)) :: (a -> b -> c -> Eval z))
77
78instance (Boxable a, Boxable z) => MethodPrimable (a -> z) a where
79    asPrim f x _ = return (mkVal (f x))
80
81instance (Boxable a, Boxable z) => MethodPrimable (a -> Eval z) a where
82    asPrim f x _ = fmap mkVal (f x)
83
84instance (Boxable a, Boxable z) => MethodPrimable (a -> Val -> Eval z) a where
85    asPrim f x args = fmap mkVal (f x (args !: 0))
86
87instance (Boxable a, Boxable z) => MethodPrimable (a -> [:Val:] -> Eval z) a where
88    asPrim f x args = fmap mkVal (f x args)
89
90instance (Boxable a, Boxable z) => MethodPrimable (a -> [Val] -> Eval z) a where
91    asPrim f x args = fmap mkVal (f x (cast args))
92
93instance (Boxable a, Boxable b, Boxable z) => MethodPrimable (a -> [b] -> Eval z) a where
94    asPrim f x args = do
95        args' <- mapM coerceVal (cast args)
96        fmap mkVal (f x args')
97
98instance (Boxable a, Boxable b, Boxable z) => MethodPrimable (a -> b -> Eval z) a where
99    asPrim f x args = do
100        y <- coerceVal (args !: 0)
101        fmap mkVal (f x y)
102
103instance (Boxable a, Boxable b, Boxable c, Boxable z) => MethodPrimable (a -> b -> c -> Eval z) a where
104    asPrim f x args = do
105        y <- coerceVal (args !: 0)
106        z <- coerceVal (args !: 1)
107        fmap mkVal (f x y z)
108
109(...) :: MethodPrimable a b => String -> a -> (ID, MethodPrim b)
110(...) x y = (_cast x, asPrim y)
111
112(!!!) :: Boxable b => String -> (a -> Eval b) -> (ID, a -> Eval Val)
113(!!!) x y = (_cast x, mkValM . y)
114
115mkValM :: Boxable a => Eval a -> Eval Val
116mkValM x = do
117    x' <- x
118    return $ MkInvocant x' (class_interface (classOf x'))
119
120mkBoxClass :: Boxable a => String -> [(ID, MethodPrim a)] -> PureClass
121mkBoxClass cls methods = newMOClass MkMOClass
122    { moc_parents         = []
123    , moc_roles           = []
124    , moc_attributes      = []
125    , moc_public_methods  = newCollection' methodName $ map mkBoxMethod methods
126    , moc_private_methods = newCollection []
127    , moc_name            = _cast cls
128    }
129
130
131
132-- | Variant of @mkBoxClass@ making use of the fixed-point combinator
133-- to tye in its "self", and, that adds the standard HOW and WHICH methods.
134-- mkPureClass :: (Boxable a) => String -> [(ID, MethodPrim a)] -> PureClass
135mkPureClass :: Boxable a => String -> [(ID, MethodPrim a)] -> PureClass
136mkPureClass cls methods = fix . (mkBoxClass cls .) $ \self -> flip (++) methods
137    [ ""        ... mkVal self
138    , "ITEM"    ... id
139    , "LIST"    ... id
140    ]
141
142raiseWhatError :: String -> a
143raiseWhatError = error
144
145mkBoxMethod :: forall a. Boxable a => (ID, MethodPrim a) -> AnyMethod Eval
146mkBoxMethod (meth, fun) = MkMethod $ MkSimpleMethod
147    { sm_name       = meth
148    , sm_definition = MkMethodCompiled $ \args -> do
149        inv  <- fromInvocant args :: Eval a
150        fun inv $ concatMapP f_positionals (c_feeds args)
151    }
152
153type PureClass = MOClass Eval
154
155instance (Show a, Typeable a, Ord a) => Boxable (Maybe a)
156
157instance Boxable a => Boxable [a]
158instance Boxable a => Boxable [:a:]
159
160instance Boxable ID
161instance Boxable PureClass where
162    classOf _ = _PureClass
163
164_PureClass :: PureClass
165_PureClass = mkPureClass "Class"
166    [ "methods"     ... ((filter (/= nullID) . map methodName . all_methods) :: PureClass -> [ID])
167    ]
168
169instance ((:>:) Call) String where
170    cast = (`MkMethodInvocation` CaptSub{ c_feeds = [::] }) . _cast
171
172instance ((:>:) Call) ByteString where
173    cast = (`MkMethodInvocation` CaptSub{ c_feeds = [::] }) . cast
174
175instance ((:>:) Call (ByteString, [Val], AtomMap Val)) where
176    cast (meth, pos, named) = MkMethodInvocation (cast meth) CaptSub
177        { c_feeds = [: MkFeed (toP pos) (AtomMap.map (\x -> [:x:]) named) :]}
Note: See TracBrowser for help on using the browser.