1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE StandaloneDeriving #-} -- For Show (ParsingError inp)
3 {-# LANGUAGE TemplateHaskell #-}
4 {-# LANGUAGE UnboxedTuples #-} -- For nextInput
5 {-# LANGUAGE UndecidableInstances #-} -- For Show (ParsingError inp)
6 module Symantic.Parser.Automaton.Eval where
8 import Control.Monad (Monad(..))
9 import Data.Bool (Bool)
10 import Data.Char (Char)
11 import Data.Either (Either(..))
12 import Data.Eq (Eq(..))
13 import Data.Function (($))
14 -- import Data.Functor ((<$>))
16 import Data.Maybe (Maybe(..))
17 import Data.Monoid (Monoid(..))
18 import Data.Ord (Ord, Ordering(..))
19 import Data.Semigroup (Semigroup(..))
21 import Language.Haskell.TH (CodeQ, Code(..))
23 import Text.Show (Show(..))
24 import qualified Data.Eq as Eq
25 import qualified Data.Set as Set
26 import qualified Language.Haskell.TH.Syntax as TH
28 import Symantic.Univariant.Trans
29 import Symantic.Parser.Grammar.Combinators (ErrorItem(..))
30 import Symantic.Parser.Automaton.Input
31 import Symantic.Parser.Automaton.Instructions
32 import qualified Symantic.Parser.Staging as H
35 -- | Generate the 'CodeQ' parsing the input.
36 newtype Eval inp vs es a = Eval { unEval ::
37 EvalCtx inp vs es a ->
38 CodeQ (Either (ParsingError inp) a)
41 -- ** Type 'ParsingError'
43 = ParsingErrorStandard
44 { parsingErrorOffset :: Offset
45 , parsingErrorUnexpected :: Maybe (InputToken inp)
46 , parsingErrorExpecting :: Set (ErrorItem (InputToken inp))
48 deriving instance Show (InputToken inp) => Show (ParsingError inp)
51 newtype Hints inp = Hints [Set (ErrorItem (InputToken inp))]
52 instance Semigroup (Hints t) where
53 Hints xs <> Hints ys = Hints $ xs <> ys
54 instance Monoid (Hints t) where
61 -- | An “OK” continuation to alter
62 (a -> State s e -> Hints t -> m b) ->
63 -- | Altered “OK” continuation
64 (a -> State s e -> Hints t -> m b)
65 accHints hs1 c x s hs2 = c x s (hs1 <> hs2)
68 toHints :: Offset -> ParsingError inp -> Hints inp
69 toHints curOff = \case
70 ParsingErrorStandard errOff _ es ->
72 then Hints (if Set.null es then [] else [es])
80 -- | Continuation to influence
81 (ParseError s e -> State s e -> m b) ->
82 -- | First argument of resulting continuation
84 -- | Second argument of resulting continuation
87 withHints (Hints hs) c e =
89 ParsingErrorStandard pos us es -> c (ParsingErrorStandard pos us (Set.unions (es : hs)))
90 {-# INLINE withHints #-}
98 {-farthestInput-}Cursor inp ->
99 {-farthestExpecting-}[ErrorItem (InputToken inp)] ->
102 Either (ParsingError inp) a
104 -- ** Type 'SubRoutine'
105 type SubRoutine inp v a =
106 {-ok-}Cont inp v a ->
108 {-ko-}FailHandler inp a ->
109 Either (ParsingError inp) a
111 -- ** Type 'FailHandler'
112 type FailHandler inp a =
113 {-failureInput-}Cursor inp ->
114 {-farthestInput-}Cursor inp ->
115 {-farthestExpecting-}[ErrorItem (InputToken inp)] ->
116 Either (ParsingError inp) a
119 -- *** Type 'FarthestError'
120 data FarthestError inp = FarthestError
121 { farthestInput :: Cursor inp
122 , farthestExpecting :: [ErrorItem (InputToken inp)]
128 Ord (InputToken inp) =>
129 Show (InputToken inp) =>
130 TH.Lift (InputToken inp) =>
131 -- InputToken inp ~ Char =>
135 Eval inp '[] ('Succ 'Zero) ret ->
136 CodeQ (Either (ParsingError inp) ret)
137 eval input (Eval k) = [||
139 -- Pattern bindings containing unlifted types
140 -- should use an outermost bang pattern.
141 let !(# init, readMore, readNext #) = $$(cursorOf input) in
142 let evalRet = \_farInp _farExp v _inp -> Right v in
143 let evalFail _failInp !farInp !farExp =
144 Left ParsingErrorStandard
145 { parsingErrorOffset = offset farInp
146 , parsingErrorUnexpected =
148 then Just (let (# c, _ #) = readNext farInp in c)
150 , parsingErrorExpecting = Set.fromList farExp
153 { valueStack = ValueStackEmpty
154 , failStack = FailStackCons [||evalFail||] FailStackEmpty
155 , retCode = [||evalRet||]
157 , nextInput = [||readNext||]
158 , moreInput = [||readMore||]
159 -- , farthestError = [||Nothing||]
160 , farthestInput = [||init||]
161 , farthestExpecting = [|| [] ||]
166 -- | This is a context only present at compile-time.
167 data EvalCtx inp vs (es::Peano) a =
168 ( TH.Lift (InputToken inp)
169 , Cursorable (Cursor inp)
170 , Show (InputToken inp)
171 -- , InputToken inp ~ Char
173 { valueStack :: ValueStack vs
174 , failStack :: FailStack inp es a
175 , retCode :: CodeQ (Cont inp a a)
176 , input :: CodeQ (Cursor inp)
177 , moreInput :: CodeQ (Cursor inp -> Bool)
178 , nextInput :: CodeQ (Cursor inp -> (# InputToken inp, Cursor inp #))
179 , farthestInput :: CodeQ (Cursor inp)
180 , farthestExpecting :: CodeQ [ErrorItem (InputToken inp)]
183 -- ** Type 'ValueStack'
184 data ValueStack vs where
185 ValueStackEmpty :: ValueStack '[]
186 ValueStackCons :: CodeQ v -> ValueStack vs -> ValueStack (v ': vs)
187 -- TODO: maybe use H.Haskell instead of CodeQ ?
188 -- as in https://github.com/j-mie6/ParsleyHaskell/popFail/3ec0986a5017866919a6404c14fe78678b7afb46
190 -- ** Type 'FailStack'
191 data FailStack inp es a where
192 FailStackEmpty :: FailStack inp 'Zero a
194 CodeQ (FailHandler inp a) ->
195 FailStack inp es a ->
196 FailStack inp ('Succ es) a
198 instance Stackable Eval where
199 push x k = Eval $ \inh -> unEval k inh
200 { valueStack = ValueStackCons (liftCode x) (valueStack inh) }
201 pop k = Eval $ \inh -> unEval k inh
202 { valueStack = let ValueStackCons _ xs = valueStack inh in xs }
203 liftI2 f k = Eval $ \inh -> unEval k inh
205 let ValueStackCons y (ValueStackCons x xs) = valueStack inh in
206 ValueStackCons (liftCode2 f x y) xs
208 swap k = Eval $ \inh -> unEval k inh
210 let ValueStackCons y (ValueStackCons x xs) = valueStack inh in
211 ValueStackCons x (ValueStackCons y xs)
213 instance Branchable Eval where
214 case_ kx ky = Eval $ \inh ->
215 let ValueStackCons v vs = valueStack inh in
218 Left x -> $$(unEval kx inh{ valueStack = ValueStackCons [||x||] vs })
219 Right y -> $$(unEval ky inh{ valueStack = ValueStackCons [||y||] vs })
221 choices fs ks kd = Eval $ \inh ->
222 let ValueStackCons v vs = valueStack inh in
223 go inh{valueStack = vs} v fs ks
225 go inh x (f:fs') (Eval k:ks') = [||
226 if $$(liftCode1 f x) then $$(k inh)
227 else $$(go inh x fs' ks')
229 go inh _ _ _ = unEval kd inh
230 instance Failable Eval where
231 fail failExp = Eval $ \inh@EvalCtx{} ->
232 let FailStackCons e _es = failStack inh in
234 let (# farInp, farExp #) =
235 case $$compareOffset $$(farthestInput inh) $$(input inh) of
236 LT -> (# $$(input inh), failExp #)
237 EQ -> (# $$(farthestInput inh), ($$(farthestExpecting inh) <> failExp) #)
238 GT -> (# $$(farthestInput inh), $$(farthestExpecting inh) #) in
241 <>" failExp="<>show @[ErrorItem Char] failExp
242 <>" farthestExpecting="<>show @[ErrorItem Char] ($$(farthestExpecting inh))
243 <>" farExp="<>show @[ErrorItem Char] farExp) $
245 $$e $$(input inh) farInp farExp
247 popFail k = Eval $ \inh ->
248 let FailStackCons _e es = failStack inh in
249 unEval k inh{failStack = es}
250 catchFail ok ko = Eval $ \inh@EvalCtx{} -> [||
251 let _ = "catchFail" in $$(unEval ok inh
252 { failStack = FailStackCons [|| \(!failInp) (!farInp) (!farExp) ->
253 -- trace ("catchFail: " <> "farExp="<>show farExp) $
255 -- Push the input as it was when entering the catchFail.
256 { valueStack = ValueStackCons (input inh) (valueStack inh)
257 -- Move the input to the failing position.
258 , input = [||failInp||]
259 -- Set the farthestInput to the farthest computed by 'fail'
260 , farthestInput = [||farInp||]
261 , farthestExpecting = [||farExp||]
266 instance Inputable Eval where
267 loadInput k = Eval $ \inh ->
268 let ValueStackCons input vs = valueStack inh in
269 unEval k inh{valueStack = vs, input}
270 pushInput k = Eval $ \inh ->
271 unEval k inh{valueStack = ValueStackCons (input inh) (valueStack inh)}
272 instance Routinable Eval where
273 call (LetName n) k = Eval $ \inh ->
275 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
276 {-ok-}(suspend k inh)
278 {-ko-}(failStack inh)
279 jump (LetName n) = Eval $ \inh ->
281 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
284 {-ko-}(failStack inh)
285 ret = Eval $ \inh -> unEval (resume (retCode inh)) inh
286 subroutine (LetName n) sub k = Eval $ \inh -> Code $ TH.unsafeTExpCoerce $ do
287 val <- TH.unTypeQ $ TH.examineCode $ [|| -- buildRec in Parsley
290 { valueStack = ValueStackEmpty
291 , failStack = FailStackCons [||ko||] FailStackEmpty
296 let decl = TH.FunD n [TH.Clause [] (TH.NormalB val) []]
297 exp <- TH.unTypeQ (TH.examineCode (unEval k inh))
298 return (TH.LetE [decl] exp)
300 callWithContinuation ::
301 {-sub-}CodeQ (SubRoutine inp v a) ->
302 {-ok-}CodeQ (Cont inp v a) ->
303 CodeQ (Cursor inp) ->
304 FailStack inp ('Succ es) a ->
305 CodeQ (Either (ParsingError inp) a)
306 callWithContinuation sub ok inp (FailStackCons ko _) =
307 [|| let _ = "callWithContinuation" in $$sub $$ok $$inp $! $$ko ||]
310 {-k-}Eval inp (v ': vs) es a ->
311 EvalCtx inp vs es a ->
313 suspend k inh = [|| let _ = "suspend" in \farInp farExp v !inp ->
315 { valueStack = ValueStackCons [||v||] (valueStack inh)
317 , farthestInput = [||farInp||]
318 , farthestExpecting = [||farExp||]
322 resume :: CodeQ (Cont inp v a) -> Eval inp (v ': vs) es a
323 resume k = Eval $ \inh ->
324 let ValueStackCons v _ = valueStack inh in
325 [|| let _ = "resume" in $$k $$(farthestInput inh) $$(farthestExpecting inh) $$v $$(input inh) ||]
327 instance Readable Eval Char where
330 maybeEmitCheck (Just 1) k
332 maybeEmitCheck Nothing ok = sat (liftCode p) ok (fail farExp)
333 maybeEmitCheck (Just n) ok = Eval $ \inh ->
334 let FailStackCons e es = failStack inh in
336 let readFail = $$(e) in -- Factorize failure code
337 $$((`unEval` inh{failStack = FailStackCons [||readFail||] es}) $ emitLengthCheck n
338 {-ok-}(sat (liftCode p) ok
345 -- Cursorable (Cursor inp) =>
346 -- InputToken inp ~ Char =>
347 Ord (InputToken inp) =>
348 TH.Lift (InputToken inp) =>
349 {-predicate-}CodeQ (InputToken inp -> Bool) ->
350 {-ok-}Eval inp (InputToken inp ': vs) ('Succ es) a ->
351 {-ko-}Eval inp vs ('Succ es) a ->
352 Eval inp vs ('Succ es) a
353 sat p ok ko = Eval $ \inh -> [||
354 let !(# c, cs #) = $$(nextInput inh) $$(input inh) in
356 then $$(unEval ok inh
357 { valueStack = ValueStackCons [||c||] (valueStack inh)
360 else let _ = "sat.else" in $$(unEval ko inh)
367 InstrPure (Char -> Bool) ->
368 Eval inp (Char ': vs) ('Succ es) a ->
369 Eval inp vs ('Succ es) a
371 bankrupt <- asks isBankrupt
372 hasChange <- asks hasCoin
373 if | bankrupt -> maybeEmitCheck (Just 1) <$> k
374 | hasChange -> maybeEmitCheck Nothing <$> local spendCoin k
375 | otherwise -> local breakPiggy (maybeEmitCheck . Just <$> asks coins <*> local spendCoin k)
377 maybeEmitCheck Nothing mk inh = sat (genDefunc p) mk (raise inh) inh
378 maybeEmitCheck (Just n) mk inh =
379 [|| let bad = $$(raise inh) in $$(emitLengthCheck n (sat (genDefunc p) mk [||bad||]) [||bad||] inh)||]
383 TH.Lift (InputToken inp) =>
384 Int -> Eval inp vs es a -> Eval inp vs es a -> Eval inp vs es a
385 emitLengthCheck 0 ok _ko = ok
386 emitLengthCheck 1 ok ko = Eval $ \inh -> [||
387 if $$(moreInput inh) $$(input inh)
388 then $$(unEval ok inh)
389 else let _ = "sat.length-check.else" in $$(unEval ko inh)
392 emitLengthCheck n ok ko inh = Eval $ \inh -> [||
393 if $$moreInput ($$shiftRight $$(input inh) (n - 1))
394 then $$(unEval ok inh)
395 else $$(unEval ko inh {farthestExpecting = [||farExp||]})
400 liftCode :: InstrPure a -> CodeQ a
402 {-# INLINE liftCode #-}
404 liftCode1 :: InstrPure (a -> b) -> CodeQ a -> CodeQ b
405 liftCode1 p a = case p of
406 InstrPureSameOffset -> [|| $$sameOffset $$a ||]
407 InstrPureHaskell h -> go a h
409 go :: CodeQ a -> H.Haskell (a -> b) -> CodeQ b
411 (H.:$) -> [|| \x -> $$qa x ||]
412 (H.:.) -> [|| \g x -> $$qa (g x) ||]
413 H.Flip -> [|| \x y -> $$qa y x ||]
414 (H.:.) H.:@ f H.:@ g -> [|| $$(go (go qa g) f) ||]
415 H.Const -> [|| \_ -> $$qa ||]
416 H.Flip H.:@ H.Const -> H.id
417 h@(H.Flip H.:@ _f) -> [|| \x -> $$(liftCode2 (InstrPureHaskell h) qa [||x||]) ||]
418 H.Eq x -> [|| $$(trans x) Eq.== $$qa ||]
420 h -> [|| $$(trans h) $$qa ||]
422 liftCode2 :: InstrPure (a -> b -> c) -> CodeQ a -> CodeQ b -> CodeQ c
423 liftCode2 p a b = case p of
424 InstrPureSameOffset -> [|| $$sameOffset $$a $$b ||]
425 InstrPureHaskell h -> go a b h
427 go :: CodeQ a -> CodeQ b -> H.Haskell (a -> b -> c) -> CodeQ c
429 (H.:$) -> [|| $$qa $$qb ||]
430 (H.:.) -> [|| \x -> $$qa ($$qb x) ||]
431 H.Flip -> [|| \x -> $$qa x $$qb ||]
432 H.Flip H.:@ H.Const -> [|| $$qb ||]
433 H.Flip H.:@ f -> go qb qa f
434 H.Const -> [|| $$qa ||]
435 H.Cons -> [|| $$qa : $$qb ||]
436 h -> [|| $$(trans h) $$qa $$qb ||]