1 {-# LANGUAGE ConstraintKinds #-} -- For Executable
2 {-# LANGUAGE PatternSynonyms #-}
3 {-# LANGUAGE ViewPatterns #-}
4 module Symantic.Parser.Automaton.Instructions where
6 import Data.Bool (Bool)
7 import Data.Char (Char)
8 import Data.Either (Either)
10 import Data.Function (($), (.))
11 import Text.Show (Show)
12 import qualified Data.Functor as Functor
13 import qualified Language.Haskell.TH.Syntax as TH
14 import qualified Symantic.Parser.Staging as Hask
16 import Symantic.Parser.Grammar
17 import Symantic.Univariant.Trans
19 import Prelude (undefined)
21 -- * Class 'InputPosition'
23 class InputPosition inp where
24 instance InputPosition ()
27 -- | 'Instr'uctions for the 'Automaton'.
28 data Instr input valueStack (exceptionStack::Peano) returnValue a where
29 -- | @('Push' x k)@ pushes @(x)@ on the value-stack
30 -- and continues with the next 'Instr'uction @(k)@.
33 Instr inp (x ': vs) es ret a ->
35 -- | @('Pop' k)@ pushes @(x)@ on the value-stack.
37 Instr inp vs es ret a ->
38 Instr inp (x ': vs) es ret a
39 -- | @('LiftI2' f k)@ pops two values from the value-stack,
40 -- and pushes the result of @(f)@ applied to them.
42 InstrPure (x -> y -> z) ->
43 Instr inp (z : vs) es ret a ->
44 Instr inp (y : x : vs) es ret a
45 -- | @('Fail')@ raises an error from the exception-stack.
47 Instr inp vs ('Succ es) ret a
48 -- | @('Commit' k)@ removes an exception from the exception-stack
49 -- and continues with the next 'Instr'uction @(k)@.
51 Instr inp vs es ret a ->
52 Instr inp vs ('Succ es) ret a
53 -- | @('Catch' l r)@ tries the @(l)@ 'Instr'uction,
54 -- if it raises an exception, catches it,
55 -- pushes the input on the value-stack
56 -- and continues with the @(r)@ 'Instr'uction.
58 Instr inp vs ('Succ es) ret a ->
59 Instr inp (inp ': vs) es ret a ->
61 -- | @('Seek' k)@ removes the input from the value-stack
62 -- and continues with the next 'Instr'uction @(k)@.
64 Instr inp vs es r a ->
65 Instr inp (inp : vs) es r a
66 -- | @('Tell' k)@ pushes the input @(inp)@ on the value-stack
67 -- and continues with the next 'Instr'uction @(k)@.
69 Instr inp (inp ': vs) es ret a ->
73 Instr inp (x ': vs) es r a ->
74 Instr inp (y ': vs) es r a ->
75 Instr inp (Either x y ': vs) es r a
76 -- | @('Swap' k)@ pops two values on the value-stack,
77 -- pushes the first popped-out, then the second,
78 -- and continues with the next 'Instr'uction @(k)@.
80 Instr inp (x ': y ': vs) es r a ->
81 Instr inp (y ': x ': vs) es r a
82 -- | @('Choices' ps bs d)@.
84 [InstrPure (x -> Bool)] ->
85 [Instr inp vs es ret a] ->
86 Instr inp vs es ret a ->
87 Instr inp (x ': vs) es ret a
91 Instr inp vs ('Succ es) ret a ->
92 Instr inp vs ('Succ es) ret a
96 Instr inp '[] ('Succ es) ret a
100 Instr inp (x ': vs) ('Succ es) ret a ->
101 Instr inp vs ('Succ es) ret a
102 -- | @('Ret')@ returns the value in a singleton value-stack.
104 Instr inp '[ret] es ret a
107 InstrPure (Char -> Bool) ->
108 Instr inp (Char ': vs) ('Succ es) ret a ->
109 Instr inp vs ('Succ es) ret a
111 -- ** Type 'InstrPure'
113 = InstrPureHaskell (Hask.Haskell a)
114 | InstrPureSameOffset
118 newtype Addr a = Addr { unLabel :: TH.Name }
121 -- * Class 'Executable'
122 type Executable repr =
131 -- ** Class 'Stackable'
132 class Stackable (repr :: * -> [*] -> Peano -> * -> * -> *) where
135 repr inp (x ': vs) n ret a ->
138 repr inp vs n ret a ->
139 repr inp (x ': vs) n ret a
141 InstrPure (x -> y -> z) ->
142 repr inp (z ': vs) es ret a ->
143 repr inp (y ': x ': vs) es ret a
145 repr inp (x ': y ': vs) n r a ->
146 repr inp (y ': x ': vs) n r a
148 -- ** Class 'Branchable'
149 class Branchable (repr :: * -> [*] -> Peano -> * -> * -> *) where
151 repr inp (x ': vs) n r a ->
152 repr inp (y ': vs) n r a ->
153 repr inp (Either x y ': vs) n r a
155 [InstrPure (x -> Bool)] ->
156 [repr inp vs es ret a] ->
157 repr inp vs es ret a ->
158 repr inp (x ': vs) es ret a
160 -- ** Class 'Exceptionable'
161 class Exceptionable (repr :: * -> [*] -> Peano -> * -> * -> *) where
162 fail :: repr inp vs ('Succ es) ret a
164 repr inp vs es ret a ->
165 repr inp vs ('Succ es) ret a
167 repr inp vs ('Succ es) ret a ->
168 repr inp (inp ': vs) es ret a ->
171 -- ** Class 'Inputable'
172 class Inputable (repr :: * -> [*] -> Peano -> * -> * -> *) where
174 repr inp vs es r a ->
175 repr inp (inp ': vs) es r a
177 repr inp (inp ': vs) es ret a ->
180 -- ** Class 'Routinable'
181 class Routinable (repr :: * -> [*] -> Peano -> * -> * -> *) where
184 repr inp vs ('Succ es) ret a ->
185 repr inp vs ('Succ es) ret a
188 repr inp (x ': vs) ('Succ es) ret a ->
189 repr inp vs ('Succ es) ret a
191 repr inp '[ret] es ret a
194 repr inp '[] ('Succ es) ret a
196 -- ** Class 'Readable'
197 class Readable (repr :: * -> [*] -> Peano -> * -> * -> *) where
199 InstrPure (Char -> Bool) ->
200 repr inp (Char ': vs) ('Succ es) ret a ->
201 repr inp vs ('Succ es) ret a
205 Trans (Instr inp vs es ret) (repr inp vs es ret) where
207 Push x k -> push x (trans k)
208 Pop k -> pop (trans k)
209 LiftI2 f k -> liftI2 f (trans k)
211 Commit k -> commit (trans k)
212 Catch l r -> catch (trans l) (trans r)
213 Seek k -> seek (trans k)
214 Tell k -> tell (trans k)
215 Case l r -> case_ (trans l) (trans r)
216 Swap k -> swap (trans k)
217 Choices ps bs d -> choices ps (trans Functor.<$> bs) (trans d)
218 Label n k -> label n (trans k)
220 Call n (k::Instr inp (x ': vs) ('Succ es') ret a) ->
221 call n (trans k :: repr inp (x ': vs) ('Succ es') ret a)
223 Read p k -> read p (trans k)
226 -- | Type-level natural numbers, using the Peano recursive encoding.
227 data Peano = Zero | Succ Peano
231 InstrPure (x -> y) ->
232 Instr inp (y ': xs) es ret a ->
233 Instr inp (x ': xs) es ret a
234 pattern Fmap f k = Push f (LiftI2 (InstrPureHaskell (Hask.Flip Hask.:@ (Hask.:$))) k)
236 -- | @('App' k)@ pops @(x)@ and @(x2y)@ from the value-stack,
237 -- pushes @(x2y x)@ and continues with the next 'Instr'uction @(k)@.
238 pattern App :: Instr inp (y : vs) es ret a -> Instr inp (x : (x -> y) : vs) es ret a
239 pattern App k = LiftI2 (InstrPureHaskell (Hask.:$)) k
241 -- | @('If' ok ko)@ pops a 'Bool' from the value-stack
242 -- and continues either with the 'Instr'uction @(ok)@ if it is 'True'
243 -- or @(ko)@ otherwise.
244 pattern If :: Instr inp vs es ret a -> Instr inp vs es ret a -> Instr inp (Bool ': vs) es ret a
245 pattern If ok ko = Choices [InstrPureHaskell Hask.Id] [ok] ko
247 parsecHandler :: InputPosition inp => Instr inp vs ('Succ es) ret a -> Instr inp (inp : vs) ('Succ es) ret a
248 parsecHandler k = Tell (LiftI2 InstrPureSameOffset (If k Fail))
250 -- * Type 'Automaton'
251 -- | Making the control-flow explicit.
252 data Automaton inp a x = Automaton { unAutomaton ::
254 {-next-}Instr inp (x ': vs) ('Succ es) ret a ->
255 Instr inp vs ('Succ es) ret a
259 forall inp a es repr.
261 Automaton inp a a -> (repr inp '[] ('Succ es) a) a
263 trans @(Instr inp '[] ('Succ es) a) .
267 instance Applicable (Automaton inp a) where
268 pure x = Automaton $ Push (InstrPureHaskell x)
269 Automaton f <*> Automaton x = Automaton $ f . x . App
270 liftA2 f (Automaton x) (Automaton y) = Automaton $
271 x . y . LiftI2 (InstrPureHaskell f)
272 Automaton x *> Automaton y = Automaton $ x . Pop . y
273 Automaton x <* Automaton y = Automaton $ x . y . Pop
276 Alternable (Automaton inp a) where
277 empty = Automaton $ \_k -> Fail
278 Automaton l <|> Automaton r = Automaton $ \k ->
280 Catch (l (Commit k)) (parsecHandler (r k))
281 try (Automaton x) = Automaton $ \k ->
282 Catch (x (Commit k)) (Seek Fail)
283 instance Charable (Automaton inp a) where
284 satisfy p = Automaton $ Read (InstrPureHaskell p)
285 instance Selectable (Automaton inp a) where
286 branch (Automaton lr) (Automaton l) (Automaton r) = Automaton $ \k ->
288 lr (Case (l (Swap (App k)))
290 instance Matchable (Automaton inp a) where
291 conditional ps bs (Automaton a) (Automaton default_) =
294 a (Choices (InstrPureHaskell Functor.<$> ps)
295 ((\b -> unAutomaton b k) Functor.<$> bs)
297 instance Lookable (Automaton inp a) where
298 look (Automaton x) = Automaton $ \k ->
299 Tell (x (Swap (Seek k)))
300 negLook (Automaton x) = Automaton $ \k ->
301 Catch (Tell (x (Pop (Seek (Commit Fail)))))
302 (Seek (Push (InstrPureHaskell Hask.unit) k))
303 instance Letable TH.Name (Automaton inp a) where
304 def n (Automaton x) = Automaton $ \k ->
306 ref _isRec n = Automaton $ \case
309 instance Foldable (Automaton inp a) where
311 chainPost = undefined