@@ -5,4 +5,128 @@ title: Parsley
55
66{% include toc.html %}
77
8- https://hackage.haskell.org/package/parsley
8+ From the documentation:
9+
10+ > [ parsley] ( https://hackage.haskell.org/package/parsley ) is a staged selective
11+ > parser combinator library, which means it does not support monadic operations,
12+ > and relies on Typed Template Haskell to generate very fast code.
13+
14+ # Definition
15+
16+ Let's seen how it's defined:
17+
18+ ``` haskell
19+ newtype Parser a = Parser { unParser :: Fix (Combinator :+: ScopeRegister ) a }
20+
21+ -- Core datatype
22+ data Combinator (k :: Type -> Type ) (a :: Type ) where
23+ Pure :: Defunc a -> Combinator k a
24+ Satisfy :: Defunc (Char -> Bool ) -> Combinator k Char
25+ (:<*>:) :: k (a -> b ) -> k a -> Combinator k b
26+ (:*>:) :: k a -> k b -> Combinator k b
27+ (:<*:) :: k a -> k b -> Combinator k a
28+ (:<|>:) :: k a -> k a -> Combinator k a
29+ Empty :: Combinator k a
30+ Try :: k a -> Combinator k a
31+ LookAhead :: k a -> Combinator k a
32+ Let :: Bool -> MVar a -> Combinator k a
33+ NotFollowedBy :: k a -> Combinator k ()
34+ Branch :: k (Either a b ) -> k (a -> c ) -> k (b -> c ) -> Combinator k c
35+ Match :: k a -> [Defunc (a -> Bool )] -> [k b ] -> k b -> Combinator k b
36+ Loop :: k () -> k a -> Combinator k a
37+ MakeRegister :: ΣVar a -> k a -> k b -> Combinator k b
38+ GetRegister :: ΣVar a -> Combinator k a
39+ PutRegister :: ΣVar a -> k a -> Combinator k ()
40+ Position :: PosSelector -> Combinator k Int
41+ Debug :: String -> k a -> Combinator k a
42+ MetaCombinator :: MetaCombinator -> k a -> Combinator k a
43+ ```
44+
45+ Clearly , that's the complete opposite approach of everything we have seen so
46+ far, each operation has a constructor.
47+
48+ We can also have a look at their associated types:
49+
50+ ```haskell
51+
52+ data ScopeRegister (k :: Type -> Type ) (a :: Type ) where
53+ ScopeRegister :: k a -> (forall r . Reg r a -> k b ) -> ScopeRegister k b
54+
55+ data PosSelector where
56+ Line :: PosSelector
57+ Col :: PosSelector
58+
59+ {-|
60+ This is an opaque representation of a parsing register.
61+ It is the abstracted representation of a runtime storage location.
62+ -}
63+ newtype Reg (r :: Type ) a = Reg (ΣVar a )
64+
65+ data MetaCombinator where
66+ -- | After this combinator exits, a cut has happened
67+ Cut :: MetaCombinator
68+ -- | This combinator requires a cut from below to respect parsec semantics
69+ RequiresCut :: MetaCombinator
70+ -- | This combinator denotes that within its scope, cut semantics are not enforced
71+ CutImmune :: MetaCombinator
72+
73+ {-|
74+ An identifier representing concrete registers and mutable state.
75+ -}
76+ newtype ΣVar (a :: Type ) = ΣVar IΣVar
77+
78+ {-|
79+ Underlying untyped identifier, which is numeric but otherwise opaque.
80+ -}
81+ newtype IΣVar = IΣVar Word64 deriving newtype (Ord , Eq , Num , Enum , Show , Ix )
82+
83+ {-|
84+ This datatype is useful for providing an /inspectable/ representation of common Haskell functions.
85+ -}
86+ data Defunc a -- complex implementation
87+
88+ ```
89+
90+ Not particularly interesting, but it is very detailed.
91+
92+ # Running the parser
93+
94+ We can have a look at how everything is used, from the example:
95+
96+ ```haskell
97+ parseOut :: ByteString -> Maybe [Out ]
98+ parseOut = $$ (Parsley. parse myParser)
99+ ```
100+
101+ Then we expect the ` Template ` work to be here:
102+
103+ ``` haskell
104+ parse :: (Trace , Input input ) => Parser a -> Code (input -> Maybe a )
105+ parse p = [||\ input -> $$ (eval [|| input|| ] (compile (try p) codeGen))|| ]
106+ ```
107+
108+ The implementation is quite complex, but it'll hopefully help to get a better picture:
109+
110+ ``` haskell
111+ {-|
112+ Translates a parser represented with combinators into its machine representation.
113+ -}
114+ {-# INLINEABLE codeGen #-}
115+ codeGen :: Trace
116+ => Maybe (MVar x ) -- ^ The name of the parser, if it exists.
117+ -> Fix Combinator x -- ^ The definition of the parser.
118+ -> Set SomeΣVar -- ^ The free registers it requires to run.
119+ -> IMVar -- ^ The binding identifier to start name generation from.
120+ -> LetBinding o a x
121+
122+ eval :: forall o a . (Trace , Ops o ) => Code (InputDependant o ) -> LetBinding o a a -> DMap MVar (LetBinding o a ) -> Code (Maybe a )
123+
124+ compile :: forall compiled a . Trace => Parser a -> (forall x . Maybe (MVar x ) -> Fix Combinator x -> Set IΣVar -> IMVar -> IΣVar -> compiled x ) -> (compiled a , DMap MVar compiled )
125+ ```
126+
127+ The idea is to compile `Combinator ` to `Template `'s `Code ` through a complete machinery.
128+
129+ # Conclusion
130+
131+ The special feature of `parsley` is to be mostly working at compile- time,
132+ making the implementation far more complex.
0 commit comments