1 {-# LANGUAGE OverloadedStrings #-}
2 {-# LANGUAGE UndecidableInstances #-} -- For ShowLetName
3 module Symantic.Parser.Machine.View where
5 import Data.Bool (Bool(..))
6 import Data.Either (Either(..))
7 import Data.Function (($), (.), id, on)
8 import Data.Functor ((<$>))
9 import Data.Kind (Type)
10 import Data.Ord (Ord(..))
11 import Data.Semigroup (Semigroup(..))
12 import Data.String (String)
13 import Data.Tuple (fst)
14 import Text.Show (Show(..))
15 import qualified Data.HashMap.Strict as HM
16 import qualified Data.List as List
17 import qualified Data.Map.Strict as Map
18 import qualified Data.Set as Set
19 import qualified Data.Tree as Tree
20 import qualified Language.Haskell.TH.Syntax as TH
21 import Prelude (error)
23 import Symantic.Parser.Grammar.Combinators (UnscopedRegister(..))
24 import Symantic.Parser.Grammar.ObserveSharing
25 import Symantic.Parser.Machine.Instructions
26 import Symantic.ObserveSharing (SomeLet(..))
27 import Symantic.Parser.Machine.Generate
29 -- * Type 'ViewMachine'
30 data ViewMachine (showName::Bool) inp (vs:: [Type]) a
32 { viewGen :: Gen inp vs a
33 -- ^ Provide 'GenAnalysis', which is important for debugging
34 -- and improving golden tests, see 'viewInstrCmd'.
37 LetRecs TH.Name GenAnalysis -> -- Output of 'runOpenRecs'.
38 Tree.Forest (String, String) ->
39 Tree.Forest (String, String)
43 ViewMachine sN inp vs a ->
44 ViewMachine sN inp vs a
47 -- | Helper to view a command.
49 Either TH.Name (Gen inp vs a) ->
51 LetRecs TH.Name GenAnalysis ->
52 (String, String) -> Tree.Forest (String, String) -> Tree.Tree (String, String)
53 viewInstrCmd gen ct lm (n, no) = Tree.Node $ (n
54 <> "\nminReads="<>showsPrec 11 (minReads ga) ""
55 <> "\nmayRaise="<>showsPrec 11 (Map.keys (mayRaise ga)) ""
59 Right r -> (\f -> f ct) $ genAnalysis r $ (\f _ct -> f) <$> lm
60 Left l -> HM.findWithDefault (error (show (l, HM.keys lm))) l lm
62 -- | Helper to view an argument.
63 viewInstrArg :: String -> Tree.Forest (String, String) -> Tree.Tree (String, String)
64 viewInstrArg n = Tree.Node $ ("<"<>n<>">", "")
66 instance Show (ViewMachine sN inp vs a) where
67 show vm = List.unlines $ drawTrees $
68 unViewMachine vm [] (runOpenRecs (genAnalysisByLet (viewGen vm))) []
70 draw :: Tree.Tree (String, String) -> [String]
71 draw (Tree.Node (x, n) ts0) =
72 shift "" " " (List.zipWith (<>) (List.lines x) (n : List.repeat "")) <>
73 shift "| " "| " (drawTrees ts0)
75 drawTrees [t] = draw t
76 drawTrees (t:ts) = draw t <> drawTrees ts
77 shift ind0 ind = List.zipWith (<>) (ind0 : List.repeat ind)
79 instance InstrValuable (ViewMachine sN) where
80 pushValue a k = ViewMachine
81 { unViewMachine = \ct lm next ->
82 viewInstrCmd (Right gen) ct lm ("pushValue "<>showsPrec 10 a "", "") [] :
83 unViewMachine k ct lm next
85 } where gen = pushValue a (viewGen k)
86 popValue k = ViewMachine
87 { unViewMachine = \ct lm next ->
88 viewInstrCmd (Right gen) ct lm ("popValue", "") [] :
89 unViewMachine k ct lm next
91 } where gen = popValue (viewGen k)
92 lift2Value f k = ViewMachine
93 { unViewMachine = \ct lm next ->
94 viewInstrCmd (Right gen) ct lm ("lift2Value "<>showsPrec 10 f "", "") [] :
95 unViewMachine k ct lm next
97 } where gen = lift2Value f (viewGen k)
98 swapValue k = ViewMachine
99 { unViewMachine = \ct lm next ->
100 viewInstrCmd (Right gen) ct lm ("swapValue", "") [] :
101 unViewMachine k ct lm next
103 } where gen = swapValue (viewGen k)
104 instance InstrExceptionable (ViewMachine sN) where
105 raise exn = ViewMachine
106 { unViewMachine = \ct lm next ->
107 viewInstrCmd (Right gen) ct lm ("raise "<>show exn, "") [] : next
109 } where gen = raise exn
110 fail flr = ViewMachine
111 { unViewMachine = \ct lm next ->
112 viewInstrCmd (Right gen) ct lm ("fail "<>show (Set.toList flr), "") [] : next
114 } where gen = fail flr
115 commit exn k = ViewMachine
116 { unViewMachine = \ct lm next ->
117 viewInstrCmd (Right gen) ct lm ("commit "<>show exn, "") [] :
118 unViewMachine k ct lm next
120 } where gen = commit exn (viewGen k)
121 catch exn ok ko = ViewMachine
122 { unViewMachine = \ct lm next ->
123 viewInstrCmd (Right gen) ct lm ("catch "<>show exn, "")
124 [ viewInstrArg "ok" (unViewMachine ok ct lm [])
125 , viewInstrArg "ko" (unViewMachine ko ct lm [])
128 } where gen = catch exn (viewGen ok) (viewGen ko)
129 instance InstrBranchable (ViewMachine sN) where
130 caseBranch l r = ViewMachine
131 { unViewMachine = \ct lm next ->
132 viewInstrCmd (Right gen) ct lm ("case", "")
133 [ viewInstrArg "left" (unViewMachine l ct lm [])
134 , viewInstrArg "right" (unViewMachine r ct lm [])
137 } where gen = caseBranch (viewGen l) (viewGen r)
138 choicesBranch bs d = ViewMachine
139 { unViewMachine = \ct lm next ->
140 viewInstrCmd (Right gen) ct lm ("choicesBranch", "") (
141 ((\(p, b) -> viewInstrArg ("branch "<>showsPrec 10 p "") $
142 unViewMachine b ct lm []) <$> bs) <>
143 [ viewInstrArg "default" (unViewMachine d ct lm []) ]
146 } where gen = choicesBranch ((viewGen <$>) <$> bs) (viewGen d)
148 ShowLetName sN TH.Name =>
149 InstrCallable (ViewMachine sN) where
150 defLet defs k = ViewMachine
151 { unViewMachine = \ct lm next ->
152 (<> unViewMachine k ct lm next) $
153 List.sortBy (compare `on` (((fst <$>) <$>) . Tree.levels)) $
154 ((\(n, SomeLet sub) ->
155 viewInstrCmd (Left n) ct lm
156 ("let", " "<>showLetName @sN n)
157 (unViewMachine sub ct lm []))
160 } where gen = defLet ((\(SomeLet x) -> SomeLet (viewGen x)) <$> defs) (viewGen k)
161 jump ln@(LetName n) = ViewMachine
162 { unViewMachine = \ct lm next ->
163 viewInstrCmd (Right gen) ct lm ("jump", " "<>showLetName @sN n) [] : next
165 } where gen = jump ln
166 call ln@(LetName n) k = ViewMachine
167 { unViewMachine = \ct lm next ->
168 viewInstrCmd (Right gen) ct lm ("call", " "<>showLetName @sN n) [] :
169 unViewMachine k (n:ct) lm next
171 } where gen = call ln (viewGen k)
173 { unViewMachine = \ct lm next ->
174 viewInstrCmd (Right gen) ct lm ("ret", "") [] : next
178 ShowLetName sN TH.Name =>
179 InstrJoinable (ViewMachine sN) where
180 defJoin ln@(LetName n) j k = ViewMachine
181 { unViewMachine = \ct lm next ->
182 viewInstrCmd (Left n) ct lm
183 ("join", " "<>showLetName @sN n)
184 (unViewMachine j ct lm []) :
185 unViewMachine k (n:ct) lm next
187 } where gen = defJoin ln (viewGen j) (viewGen k)
188 refJoin ln@(LetName n) = ViewMachine
189 { unViewMachine = \ct lm next ->
190 viewInstrCmd (Right gen) ct lm ("refJoin", " "<>showLetName @sN n) [] : next
192 } where gen = refJoin ln
193 instance InstrInputable (ViewMachine sN) where
194 pushInput k = ViewMachine
195 { unViewMachine = \ct lm next ->
196 viewInstrCmd (Right gen) ct lm ("pushInput", "") [] :
197 unViewMachine k ct lm next
199 } where gen = pushInput (viewGen k)
200 loadInput k = ViewMachine
201 { unViewMachine = \ct lm next ->
202 viewInstrCmd (Right gen) ct lm ("loadInput", "") [] :
203 unViewMachine k ct lm next
205 } where gen = loadInput (viewGen k)
207 InstrReadable tok Gen =>
208 InstrReadable tok (ViewMachine sN) where
209 read es p k = ViewMachine
210 { unViewMachine = \ct lm next ->
211 viewInstrCmd (Right gen) ct lm ("read "<>showsPrec 10 p "", "") [] :
212 unViewMachine k ct lm next
214 } where gen = read es p (viewGen k)
216 ShowLetName sN TH.Name =>
217 InstrIterable (ViewMachine sN) where
218 iter jumpName@(LetName n) ok ko = ViewMachine
219 { unViewMachine = \ct lm next ->
220 viewInstrCmd (Right gen) ct lm ("iter", " "<>showLetName @sN n)
221 [ viewInstrArg "ok" (unViewMachine ok ct lm [])
222 , viewInstrArg "ko" (unViewMachine ko ct lm [])
225 } where gen = iter jumpName (viewGen ok) (viewGen ko)
227 ShowLetName sN TH.Name =>
228 InstrRegisterable (ViewMachine sN) where
229 newRegister reg@(UnscopedRegister r) k = ViewMachine
230 { unViewMachine = \ct lm next ->
231 viewInstrCmd (Right gen) ct lm ("newRegister", " "<>showLetName @sN r) [] :
232 unViewMachine k ct lm next
234 } where gen = newRegister reg (viewGen k)
235 readRegister reg@(UnscopedRegister r) k = ViewMachine
236 { unViewMachine = \ct lm next ->
237 viewInstrCmd (Right gen) ct lm ("readRegister", " "<>showLetName @sN r) [] :
238 unViewMachine k ct lm next
240 } where gen = readRegister reg (viewGen k)
241 writeRegister reg@(UnscopedRegister r) k = ViewMachine
242 { unViewMachine = \ct lm next ->
243 viewInstrCmd (Right gen) ct lm ("writeRegister", " "<>showLetName @sN r) [] :
244 unViewMachine k ct lm next
246 } where gen = writeRegister reg (viewGen k)