@@ -5,4 +5,128 @@ title: Parsley
5
5
6
6
{% include toc.html %}
7
7
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