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.Machine.Gen 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.Machine.Input
31 import Symantic.Parser.Machine.Instructions
32 import qualified Symantic.Parser.Staging as H
35 -- | Generate the 'CodeQ' parsing the input.
36 newtype Gen inp vs es a = Gen { unGen ::
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)
55 {-farthestInput-}Cursor inp ->
56 {-farthestExpecting-}[ErrorItem (InputToken inp)] ->
59 Either (ParsingError inp) a
61 -- ** Type 'SubRoutine'
62 type SubRoutine inp v a =
65 {-ko-}FailHandler inp a ->
66 Either (ParsingError inp) a
68 -- ** Type 'FailHandler'
69 type FailHandler inp a =
70 {-failureInput-}Cursor inp ->
71 {-farthestInput-}Cursor inp ->
72 {-farthestExpecting-}[ErrorItem (InputToken inp)] ->
73 Either (ParsingError inp) a
76 -- *** Type 'FarthestError'
77 data FarthestError inp = FarthestError
78 { farthestInput :: Cursor inp
79 , farthestExpecting :: [ErrorItem (InputToken inp)]
83 -- | @('generate' input mach)@ generates @TemplateHaskell@ code
84 -- parsing given 'input' according to given 'mach'ine.
87 Ord (InputToken inp) =>
88 Show (InputToken inp) =>
89 TH.Lift (InputToken inp) =>
90 -- InputToken inp ~ Char =>
94 Gen inp '[] ('Succ 'Zero) ret ->
95 CodeQ (Either (ParsingError inp) ret)
96 generate input (Gen k) = [||
97 -- Pattern bindings containing unlifted types
98 -- should use an outermost bang pattern.
99 let !(# init, readMore, readNext #) = $$(cursorOf input) in
100 let genRet = \_farInp _farExp v _inp -> Right v in
101 let genFail _failInp !farInp !farExp =
102 Left ParsingErrorStandard
103 { parsingErrorOffset = offset farInp
104 , parsingErrorUnexpected =
106 then Just (let (# c, _ #) = readNext farInp in c)
108 , parsingErrorExpecting = Set.fromList farExp
111 { valueStack = ValueStackEmpty
112 , failStack = FailStackCons [||genFail||] FailStackEmpty
113 , retCode = [||genRet||]
115 , nextInput = [||readNext||]
116 , moreInput = [||readMore||]
117 -- , farthestError = [||Nothing||]
118 , farthestInput = [||init||]
119 , farthestExpecting = [|| [] ||]
124 -- | This is a context only present at compile-time.
125 data GenCtx inp vs (es::Peano) a =
126 ( TH.Lift (InputToken inp)
127 , Cursorable (Cursor inp)
128 , Show (InputToken inp)
129 -- , InputToken inp ~ Char
131 { valueStack :: ValueStack vs
132 , failStack :: FailStack inp es a
133 , retCode :: CodeQ (Cont inp a a)
134 , input :: CodeQ (Cursor inp)
135 , moreInput :: CodeQ (Cursor inp -> Bool)
136 , nextInput :: CodeQ (Cursor inp -> (# InputToken inp, Cursor inp #))
137 , farthestInput :: CodeQ (Cursor inp)
138 , farthestExpecting :: CodeQ [ErrorItem (InputToken inp)]
141 -- ** Type 'ValueStack'
142 data ValueStack vs where
143 ValueStackEmpty :: ValueStack '[]
144 ValueStackCons :: CodeQ v -> ValueStack vs -> ValueStack (v ': vs)
145 -- TODO: maybe use H.Haskell instead of CodeQ ?
146 -- as in https://github.com/j-mie6/ParsleyHaskell/popFail/3ec0986a5017866919a6404c14fe78678b7afb46
148 -- ** Type 'FailStack'
149 data FailStack inp es a where
150 FailStackEmpty :: FailStack inp 'Zero a
152 CodeQ (FailHandler inp a) ->
153 FailStack inp es a ->
154 FailStack inp ('Succ es) a
156 instance Stackable Gen where
157 push x k = Gen $ \ctx -> unGen k ctx
158 { valueStack = ValueStackCons (liftCode x) (valueStack ctx) }
159 pop k = Gen $ \ctx -> unGen k ctx
160 { valueStack = let ValueStackCons _ xs = valueStack ctx in xs }
161 liftI2 f k = Gen $ \ctx -> unGen k ctx
163 let ValueStackCons y (ValueStackCons x xs) = valueStack ctx in
164 ValueStackCons (liftCode2 f x y) xs
166 swap k = Gen $ \ctx -> unGen k ctx
168 let ValueStackCons y (ValueStackCons x xs) = valueStack ctx in
169 ValueStackCons x (ValueStackCons y xs)
171 instance Branchable Gen where
172 case_ kx ky = Gen $ \ctx ->
173 let ValueStackCons v vs = valueStack ctx in
176 Left x -> $$(unGen kx ctx{ valueStack = ValueStackCons [||x||] vs })
177 Right y -> $$(unGen ky ctx{ valueStack = ValueStackCons [||y||] vs })
179 choices fs ks kd = Gen $ \ctx ->
180 let ValueStackCons v vs = valueStack ctx in
181 go ctx{valueStack = vs} v fs ks
183 go ctx x (f:fs') (Gen k:ks') = [||
184 if $$(liftCode1 f x) then $$(k ctx)
185 else $$(go ctx x fs' ks')
187 go ctx _ _ _ = unGen kd ctx
188 instance Failable Gen where
189 fail failExp = Gen $ \ctx@GenCtx{} ->
190 let FailStackCons e _es = failStack ctx in
192 let (# farInp, farExp #) =
193 case $$compareOffset $$(farthestInput ctx) $$(input ctx) of
194 LT -> (# $$(input ctx), failExp #)
195 EQ -> (# $$(farthestInput ctx), ($$(farthestExpecting ctx) <> failExp) #)
196 GT -> (# $$(farthestInput ctx), $$(farthestExpecting ctx) #) in
199 <>" failExp="<>show @[ErrorItem Char] failExp
200 <>" farthestExpecting="<>show @[ErrorItem Char] ($$(farthestExpecting ctx))
201 <>" farExp="<>show @[ErrorItem Char] farExp) $
203 $$e $$(input ctx) farInp farExp
205 popFail k = Gen $ \ctx ->
206 let FailStackCons _e es = failStack ctx in
207 unGen k ctx{failStack = es}
208 catchFail ok ko = Gen $ \ctx@GenCtx{} -> [||
209 let _ = "catchFail" in $$(unGen ok ctx
210 { failStack = FailStackCons [|| \(!failInp) (!farInp) (!farExp) ->
211 -- trace ("catchFail: " <> "farExp="<>show farExp) $
213 -- Push the input as it was when entering the catchFail.
214 { valueStack = ValueStackCons (input ctx) (valueStack ctx)
215 -- Move the input to the failing position.
216 , input = [||failInp||]
217 -- Set the farthestInput to the farthest computed by 'fail'
218 , farthestInput = [||farInp||]
219 , farthestExpecting = [||farExp||]
224 instance Inputable Gen where
225 loadInput k = Gen $ \ctx ->
226 let ValueStackCons input vs = valueStack ctx in
227 unGen k ctx{valueStack = vs, input}
228 pushInput k = Gen $ \ctx ->
229 unGen k ctx{valueStack = ValueStackCons (input ctx) (valueStack ctx)}
230 instance Routinable Gen where
231 call (LetName n) k = Gen $ \ctx ->
233 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
234 {-ok-}(suspend k ctx)
236 {-ko-}(failStack ctx)
237 jump (LetName n) = Gen $ \ctx ->
239 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
242 {-ko-}(failStack ctx)
243 ret = Gen $ \ctx -> unGen (resume (retCode ctx)) ctx
244 subroutine (LetName n) sub k = Gen $ \ctx -> Code $ TH.unsafeTExpCoerce $ do
245 val <- TH.unTypeQ $ TH.examineCode $ [|| -- buildRec in Parsley
248 { valueStack = ValueStackEmpty
249 , failStack = FailStackCons [||ko||] FailStackEmpty
254 let decl = TH.FunD n [TH.Clause [] (TH.NormalB val) []]
255 exp <- TH.unTypeQ (TH.examineCode (unGen k ctx))
256 return (TH.LetE [decl] exp)
258 callWithContinuation ::
259 {-sub-}CodeQ (SubRoutine inp v a) ->
260 {-ok-}CodeQ (Cont inp v a) ->
261 CodeQ (Cursor inp) ->
262 FailStack inp ('Succ es) a ->
263 CodeQ (Either (ParsingError inp) a)
264 callWithContinuation sub ok inp (FailStackCons ko _) =
265 [|| let _ = "callWithContinuation" in $$sub $$ok $$inp $! $$ko ||]
268 {-k-}Gen inp (v ': vs) es a ->
269 GenCtx inp vs es a ->
271 suspend k ctx = [|| let _ = "suspend" in \farInp farExp v !inp ->
273 { valueStack = ValueStackCons [||v||] (valueStack ctx)
275 , farthestInput = [||farInp||]
276 , farthestExpecting = [||farExp||]
280 resume :: CodeQ (Cont inp v a) -> Gen inp (v ': vs) es a
281 resume k = Gen $ \ctx ->
282 let ValueStackCons v _ = valueStack ctx in
283 [|| let _ = "resume" in $$k $$(farthestInput ctx) $$(farthestExpecting ctx) $$v $$(input ctx) ||]
285 instance Readable Gen Char where
288 maybeEmitCheck (Just 1) k
290 maybeEmitCheck Nothing ok = sat (liftCode p) ok (fail farExp)
291 maybeEmitCheck (Just n) ok = Gen $ \ctx ->
292 let FailStackCons e es = failStack ctx in
294 let readFail = $$(e) in -- Factorize failure code
295 $$((`unGen` ctx{failStack = FailStackCons [||readFail||] es}) $ emitLengthCheck n
296 {-ok-}(sat (liftCode p) ok
303 -- Cursorable (Cursor inp) =>
304 -- InputToken inp ~ Char =>
305 Ord (InputToken inp) =>
306 TH.Lift (InputToken inp) =>
307 {-predicate-}CodeQ (InputToken inp -> Bool) ->
308 {-ok-}Gen inp (InputToken inp ': vs) ('Succ es) a ->
309 {-ko-}Gen inp vs ('Succ es) a ->
310 Gen inp vs ('Succ es) a
311 sat p ok ko = Gen $ \ctx -> [||
312 let !(# c, cs #) = $$(nextInput ctx) $$(input ctx) in
315 { valueStack = ValueStackCons [||c||] (valueStack ctx)
318 else let _ = "sat.else" in $$(unGen ko ctx)
325 InstrPure (Char -> Bool) ->
326 Gen inp (Char ': vs) ('Succ es) a ->
327 Gen inp vs ('Succ es) a
329 bankrupt <- asks isBankrupt
330 hasChange <- asks hasCoin
331 if | bankrupt -> maybeEmitCheck (Just 1) <$> k
332 | hasChange -> maybeEmitCheck Nothing <$> local spendCoin k
333 | otherwise -> local breakPiggy (maybeEmitCheck . Just <$> asks coins <*> local spendCoin k)
335 maybeEmitCheck Nothing mk ctx = sat (genDefunc p) mk (raise ctx) ctx
336 maybeEmitCheck (Just n) mk ctx =
337 [|| let bad = $$(raise ctx) in $$(emitLengthCheck n (sat (genDefunc p) mk [||bad||]) [||bad||] ctx)||]
341 TH.Lift (InputToken inp) =>
342 Int -> Gen inp vs es a -> Gen inp vs es a -> Gen inp vs es a
343 emitLengthCheck 0 ok _ko = ok
344 emitLengthCheck 1 ok ko = Gen $ \ctx -> [||
345 if $$(moreInput ctx) $$(input ctx)
346 then $$(unGen ok ctx)
347 else let _ = "sat.length-check.else" in $$(unGen ko ctx)
350 emitLengthCheck n ok ko ctx = Gen $ \ctx -> [||
351 if $$moreInput ($$shiftRight $$(input ctx) (n - 1))
352 then $$(unGen ok ctx)
353 else $$(unGen ko ctx {farthestExpecting = [||farExp||]})
358 liftCode :: InstrPure a -> CodeQ a
360 {-# INLINE liftCode #-}
362 liftCode1 :: InstrPure (a -> b) -> CodeQ a -> CodeQ b
363 liftCode1 p a = case p of
364 InstrPureSameOffset -> [|| $$sameOffset $$a ||]
365 InstrPureHaskell h -> go a h
367 go :: CodeQ a -> H.Haskell (a -> b) -> CodeQ b
369 (H.:$) -> [|| \x -> $$qa x ||]
370 (H.:.) -> [|| \g x -> $$qa (g x) ||]
371 H.Flip -> [|| \x y -> $$qa y x ||]
372 (H.:.) H.:@ f H.:@ g -> [|| $$(go (go qa g) f) ||]
373 H.Const -> [|| \_ -> $$qa ||]
374 H.Flip H.:@ H.Const -> H.id
375 h@(H.Flip H.:@ _f) -> [|| \x -> $$(liftCode2 (InstrPureHaskell h) qa [||x||]) ||]
376 H.Eq x -> [|| $$(trans x) Eq.== $$qa ||]
378 h -> [|| $$(trans h) $$qa ||]
380 liftCode2 :: InstrPure (a -> b -> c) -> CodeQ a -> CodeQ b -> CodeQ c
381 liftCode2 p a b = case p of
382 InstrPureSameOffset -> [|| $$sameOffset $$a $$b ||]
383 InstrPureHaskell h -> go a b h
385 go :: CodeQ a -> CodeQ b -> H.Haskell (a -> b -> c) -> CodeQ c
387 (H.:$) -> [|| $$qa $$qb ||]
388 (H.:.) -> [|| \x -> $$qa ($$qb x) ||]
389 H.Flip -> [|| \x -> $$qa x $$qb ||]
390 H.Flip H.:@ H.Const -> [|| $$qb ||]
391 H.Flip H.:@ f -> go qb qa f
392 H.Const -> [|| $$qa ||]
393 H.Cons -> [|| $$qa : $$qb ||]
394 h -> [|| $$(trans h) $$qa $$qb ||]