1 {-# LANGUAGE TemplateHaskell #-}
2 {-# LANGUAGE UnboxedTuples #-}
3 module Symantic.Parser.Automaton.Eval where
5 import Control.Monad (Monad(..))
6 import Data.Bool (Bool)
7 import Data.Char (Char)
8 import Data.Either (Either(..))
9 import Data.Function (($))
10 import Data.String (String)
11 import Language.Haskell.TH (CodeQ, Code(..))
13 import qualified Data.Eq as Eq
14 import qualified Language.Haskell.TH.Syntax as TH
16 import Symantic.Univariant.Trans
17 import Symantic.Parser.Automaton.Input
18 import Symantic.Parser.Automaton.Instructions
19 import qualified Symantic.Parser.Staging as H
22 newtype Eval inp vs es a = Eval { unEval ::
23 EvalCtx inp vs es a ->
24 CodeQ (Either ParsingError a)
27 type ParsingError = String
28 type Cont inp v a = v -> inp -> Either ParsingError a
29 type SubRoutine inp v a =
30 {-cont-}Cont inp v a ->
32 ExceptionHandler inp a ->
34 type ExceptionHandler inp a = inp -> Either ParsingError a
39 Eval (Cursor inp) '[] ('Succ 'Zero) ret ->
40 CodeQ (Either ParsingError ret)
41 eval input (Eval k) = [||
43 -- Pattern bindings containing unlifted types
44 -- should use an outermost bang pattern.
45 let !(# init, more, next #) = $$(cursorOf input) in
47 { valueStack = ValueStackEmpty
48 , exceptionStack = ExceptionStackCons [|| let _ = "eval.exception" in \(!_) -> Left "fatal"||] ExceptionStackEmpty
49 , retCode = [|| let _ = "eval.retCode" in \v _inp -> Right v||]
51 , nextInput = nextInputCont [||next||]
52 , moreInput = [||more||]
57 data EvalCtx inp vs (es::Peano) a = EvalCtx
58 { valueStack :: ValueStack vs
59 , exceptionStack :: ExceptionStack inp es a
60 , retCode :: CodeQ (Cont inp a a)
62 , nextInput :: forall b. CodeQ inp -> (CodeQ Char -> CodeQ inp -> CodeQ b) -> CodeQ b
63 , moreInput :: CodeQ (inp -> Bool)
66 -- ** Type 'ValueStack'
67 data ValueStack vs where
68 ValueStackEmpty :: ValueStack '[]
69 ValueStackCons :: CodeQ v -> ValueStack vs -> ValueStack (v ': vs)
71 -- ** Type 'ExceptionStack'
72 data ExceptionStack inp es a where
73 ExceptionStackEmpty :: ExceptionStack inp 'Zero a
74 ExceptionStackCons :: CodeQ (ExceptionHandler inp a) -> ExceptionStack inp es a -> ExceptionStack inp ('Succ es) a
76 instance Stackable Eval where
77 push x k = Eval $ \inh -> unEval k inh
78 { valueStack = ValueStackCons (liftCode x) (valueStack inh) }
79 pop k = Eval $ \inh -> unEval k inh
80 { valueStack = let ValueStackCons _ xs = valueStack inh in xs }
81 liftI2 f k = Eval $ \inh -> unEval k inh
83 let ValueStackCons y (ValueStackCons x xs) = valueStack inh in
84 ValueStackCons (liftCode2 f x y) xs
86 swap k = Eval $ \inh -> unEval k inh
88 let ValueStackCons y (ValueStackCons x xs) = valueStack inh in
89 ValueStackCons x (ValueStackCons y xs)
91 instance Branchable Eval where
92 case_ kx ky = Eval $ \inh ->
93 let ValueStackCons v vs = valueStack inh in
96 Left x -> $$(unEval kx inh{ valueStack = ValueStackCons [||x||] vs })
97 Right y -> $$(unEval ky inh{ valueStack = ValueStackCons [||y||] vs })
99 choices fs ks kd = Eval $ \inh ->
100 let ValueStackCons v vs = valueStack inh in
101 go inh{valueStack = vs} v fs ks
103 go inh x (f:fs') (Eval k:ks') = [||
104 if $$(liftCode1 f x) then $$(k inh)
105 else $$(go inh x fs' ks')
107 go inh _ _ _ = unEval kd inh
108 instance Exceptionable Eval where
109 fail = Eval $ \inh ->
110 let ExceptionStackCons e _es = exceptionStack inh in
111 [|| let _ = "fail" in $$e $$(input inh) ||]
112 commit k = Eval $ \inh ->
113 let ExceptionStackCons _e es = exceptionStack inh in
114 unEval k inh{exceptionStack = es}
115 catch k h = Eval $ \inh ->
116 -- setupHandler inh (buildHandler inh h) k
117 [|| let _ = "catch" in $$(unEval k inh { exceptionStack =
118 ExceptionStackCons (buildHandler inh h) (exceptionStack inh) }) ||]
121 EvalCtx inp vs es a ->
122 {-handler-}Eval inp (inp ': vs) es a ->
123 CodeQ (ExceptionHandler inp a)
124 buildHandler inh handler = [|| let _ = "buildHandler" in \inp ->
125 $$(unEval handler inh
126 { valueStack = ValueStackCons (input inh) (valueStack inh)
131 instance Inputable Eval where
132 seek k = Eval $ \inh ->
133 let ValueStackCons input vs = valueStack inh in
134 unEval k inh{valueStack = vs, input}
135 tell k = Eval $ \inh ->
136 unEval k inh{valueStack = ValueStackCons (input inh) (valueStack inh)}
137 instance Routinable Eval where
138 call (Label n) k = Eval $ \inh ->
140 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
141 {-cont-}(suspend k inh)
144 jump (Label n) = Eval $ \inh ->
146 {-sub-}(Code (TH.unsafeTExpCoerce (return (TH.VarE n))))
147 {-cont-}(retCode inh)
150 ret = Eval $ \inh -> unEval (resume (retCode inh)) inh
151 subroutine (Label n) sub k = Eval $ \inh -> Code $ TH.unsafeTExpCoerce $ do
152 val <- TH.unTypeQ $ TH.examineCode $ [|| -- buildRec in Parsley
155 { valueStack = ValueStackEmpty
158 , exceptionStack = ExceptionStackCons [||h||] ExceptionStackEmpty
161 let decl = TH.FunD n [TH.Clause [] (TH.NormalB val) []]
162 exp <- TH.unTypeQ (TH.examineCode (unEval k inh))
163 return (TH.LetE [decl] exp)
165 callWithContinuation ::
166 {-sub-}CodeQ (SubRoutine inp v a) ->
167 {-cont-}CodeQ (Cont inp v a) ->
169 ExceptionStack inp ('Succ es) a ->
170 CodeQ (Either ParsingError a)
171 callWithContinuation sub cont inp (ExceptionStackCons h _) =
172 [|| let _ = "callWithContinuation" in $$sub $$cont $$inp $! $$h ||]
175 {-k-}Eval inp (v ': vs) es a ->
176 EvalCtx inp vs es a ->
178 suspend k inh = [|| let _ = "suspend" in \v !inp ->
180 { valueStack = ValueStackCons [||v||] (valueStack inh)
185 resume :: CodeQ (Cont inp v a) -> Eval inp (v ': vs) es a
186 resume k = Eval $ \inh ->
187 let ValueStackCons v _ = valueStack inh in
188 [|| let _ = "resume" in $$k $$v $$(input inh) ||]
190 instance Readable Eval where
193 sat (liftCode p) k fail
199 InstrPure (Char -> Bool) ->
200 Eval inp (Char ': vs) ('Succ es) a ->
201 Eval inp vs ('Succ es) a
203 bankrupt <- asks isBankrupt
204 hasChange <- asks hasCoin
205 if | bankrupt -> maybeEmitCheck (Just 1) <$> k
206 | hasChange -> maybeEmitCheck Nothing <$> local spendCoin k
207 | otherwise -> local breakPiggy (maybeEmitCheck . Just <$> asks coins <*> local spendCoin k)
209 maybeEmitCheck Nothing mk inh = sat (genDefunc p) mk (raise inh) inh
210 maybeEmitCheck (Just n) mk inh =
211 [|| let bad = $$(raise inh) in $$(emitLengthCheck n (sat (genDefunc p) mk [||bad||]) [||bad||] inh)||]
215 CodeQ (Char -> Bool) ->
216 Eval inp (Char ': vs) es a ->
219 sat p k bad = Eval $ \inh ->
220 nextInput inh (input inh) $ \c inp -> [||
224 { valueStack = ValueStackCons c (valueStack inh)
227 else $$(unEval bad inh)
231 liftCode :: InstrPure a -> CodeQ a
233 {-# INLINE liftCode #-}
235 liftCode1 :: InstrPure (a -> b) -> CodeQ a -> CodeQ b
236 liftCode1 p a = case p of
237 InstrPureSameOffset -> [|| $$same $$a ||]
238 InstrPureHaskell h -> go a h
240 go :: CodeQ a -> H.Haskell (a -> b) -> CodeQ b
242 (H.:$) -> [|| \x -> $$qa x ||]
243 (H.:.) -> [|| \g x -> $$qa (g x) ||]
244 H.Flip -> [|| \x y -> $$qa y x ||]
245 (H.:.) H.:@ f H.:@ g -> [|| $$(go (go qa g) f) ||]
246 H.Const -> [|| \_ -> $$qa ||]
247 H.Flip H.:@ H.Const -> H.id
248 h@(H.Flip H.:@ _f) -> [|| \x -> $$(liftCode2 (InstrPureHaskell h) qa [||x||]) ||]
249 H.Eq x -> [|| $$(trans x) Eq.== $$qa ||]
251 h -> [|| $$(trans h) $$qa ||]
253 liftCode2 :: InstrPure (a -> b -> c) -> CodeQ a -> CodeQ b -> CodeQ c
254 liftCode2 p a b = case p of
255 InstrPureSameOffset -> [|| $$same $$a $$b ||]
256 InstrPureHaskell h -> go a b h
258 go :: CodeQ a -> CodeQ b -> H.Haskell (a -> b -> c) -> CodeQ c
260 (H.:$) -> [|| $$qa $$qb ||]
261 (H.:.) -> [|| \x -> $$qa ($$qb x) ||]
262 H.Flip -> [|| \x -> $$qa x $$qb ||]
263 H.Flip H.:@ H.Const -> [|| $$qb ||]
264 H.Flip H.:@ f -> go qb qa f
265 H.Const -> [|| $$qa ||]
266 H.Cons -> [|| $$qa : $$qb ||]
267 h -> [|| $$(trans h) $$qa $$qb ||]