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 GHC.TypeLits (symbolVal)
15 import Text.Show (Show(..))
16 import qualified Data.HashMap.Strict as HM
17 import qualified Data.List as List
18 import qualified Data.Map.Strict as Map
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.ObserveSharing (ShowLetName(..))
24 import Symantic.Parser.Machine.Instructions
25 import Symantic.Univariant.Letable (SomeLet(..))
26 import Symantic.Parser.Machine.Generate
28 -- * Type 'ViewMachine'
29 data ViewMachine (showName::Bool) inp (vs:: [Type]) a
31 { viewGen :: Gen inp vs a
32 -- ^ Provide 'GenAnalysis', which next important for debugging
33 -- and improving golden tests, see 'viewInstrCmd'.
36 LetMap GenAnalysis -> -- Output of 'runGenAnalysis'.
37 Tree.Forest (String, String) ->
38 Tree.Forest (String, String)
42 ViewMachine sN inp vs a ->
43 ViewMachine sN inp vs a
46 -- | Helper to view a command.
48 Either TH.Name (Gen inp vs a) ->
51 (String, String) -> Tree.Forest (String, String) -> Tree.Tree (String, String)
52 viewInstrCmd gen ct lm (n, no) = Tree.Node $ (n
53 <> "\nminReads="<>showsPrec 11 (minReads ga) ""
54 <> "\nmayRaise="<>showsPrec 11 (Map.keys (mayRaise ga)) ""
58 Right r -> (\f -> f ct) $ genAnalysis r $ (\f _ct -> f) <$> lm
59 Left l -> HM.findWithDefault (error (show (l, HM.keys lm))) l lm
61 -- | Helper to view an argument.
62 viewInstrArg :: String -> Tree.Forest (String, String) -> Tree.Tree (String, String)
63 viewInstrArg n = Tree.Node $ ("<"<>n<>">", "")
65 instance Show (ViewMachine sN inp vs a) where
66 show vm = List.unlines $ drawTrees $
67 unViewMachine vm [] (runGenAnalysis (genAnalysisByLet (viewGen vm))) []
69 draw :: Tree.Tree (String, String) -> [String]
70 draw (Tree.Node (x, n) ts0) =
71 shift "" " " (List.zipWith (<>) (List.lines x) (n : List.repeat "")) <>
72 shift "| " "| " (drawTrees ts0)
74 drawTrees [t] = draw t
75 drawTrees (t:ts) = draw t <> drawTrees ts
76 shift ind0 ind = List.zipWith (<>) (ind0 : List.repeat ind)
78 instance InstrValuable (ViewMachine sN) where
79 pushValue a k = ViewMachine
80 { unViewMachine = \ct lm next ->
81 viewInstrCmd (Right gen) ct lm ("pushValue "<>showsPrec 10 a "", "") [] :
82 unViewMachine k ct lm next
84 } where gen = pushValue a (viewGen k)
85 popValue k = ViewMachine
86 { unViewMachine = \ct lm next ->
87 viewInstrCmd (Right gen) ct lm ("popValue", "") [] :
88 unViewMachine k ct lm next
90 } where gen = popValue (viewGen k)
91 lift2Value f k = ViewMachine
92 { unViewMachine = \ct lm next ->
93 viewInstrCmd (Right gen) ct lm ("lift2Value "<>showsPrec 10 f "", "") [] :
94 unViewMachine k ct lm next
96 } where gen = lift2Value f (viewGen k)
97 swapValue k = ViewMachine
98 { unViewMachine = \ct lm next ->
99 viewInstrCmd (Right gen) ct lm ("swapValue", "") [] :
100 unViewMachine k ct lm next
102 } where gen = swapValue (viewGen k)
103 instance InstrExceptionable (ViewMachine sN) where
104 raiseException lbl err = ViewMachine
105 { unViewMachine = \ct lm next ->
106 viewInstrCmd (Right gen) ct lm ("raiseException "<>show (symbolVal lbl), "") [] : next
108 } where gen = raiseException lbl err
109 popException lbl k = ViewMachine
110 { unViewMachine = \ct lm next ->
111 viewInstrCmd (Right gen) ct lm ("popException "<>show (symbolVal lbl), "") [] :
112 unViewMachine k ct lm next
114 } where gen = popException lbl (viewGen k)
115 catchException lbl ok ko = ViewMachine
116 { unViewMachine = \ct lm next ->
117 viewInstrCmd (Right gen) ct lm ("catchException "<>show (symbolVal lbl), "")
118 [ viewInstrArg "ok" (unViewMachine ok ct lm [])
119 , viewInstrArg "ko" (unViewMachine ko ct lm [])
122 } where gen = catchException lbl (viewGen ok) (viewGen ko)
123 instance InstrBranchable (ViewMachine sN) where
124 caseBranch l r = ViewMachine
125 { unViewMachine = \ct lm next ->
126 viewInstrCmd (Right gen) ct lm ("case", "")
127 [ viewInstrArg "left" (unViewMachine l ct lm [])
128 , viewInstrArg "right" (unViewMachine r ct lm [])
131 } where gen = caseBranch (viewGen l) (viewGen r)
132 choicesBranch ps bs d = ViewMachine
133 { unViewMachine = \ct lm next ->
134 viewInstrCmd (Right gen) ct lm ("choicesBranch "<>show ps, "") (
135 ((\b -> viewInstrArg "branch" $ unViewMachine b ct lm []) <$> bs) <>
136 [ viewInstrArg "default" (unViewMachine d ct lm []) ]
139 } where gen = choicesBranch ps (viewGen <$> bs) (viewGen d)
141 ShowLetName sN TH.Name =>
142 InstrCallable (ViewMachine sN) where
143 defLet defs k = ViewMachine
144 { unViewMachine = \ct lm next ->
145 (<> unViewMachine k ct lm next) $
146 List.sortBy (compare `on` (((fst <$>) <$>) . Tree.levels)) $
147 ((\(n, SomeLet sub) ->
148 viewInstrCmd (Left n) ct lm
149 ("let", " "<>showLetName @sN n)
150 (unViewMachine sub ct lm []))
153 } where gen = defLet ((\(SomeLet x) -> SomeLet (viewGen x)) <$> defs) (viewGen k)
154 jump ln@(LetName n) = ViewMachine
155 { unViewMachine = \ct lm next ->
156 viewInstrCmd (Right gen) ct lm ("jump", " "<>showLetName @sN n) [] : next
158 } where gen = jump ln
159 call ln@(LetName n) k = ViewMachine
160 { unViewMachine = \ct lm next ->
161 viewInstrCmd (Right gen) ct lm ("call", " "<>showLetName @sN n) [] :
162 unViewMachine k (n:ct) lm next
164 } where gen = call ln (viewGen k)
166 { unViewMachine = \ct lm next ->
167 viewInstrCmd (Right gen) ct lm ("ret", "") [] : next
171 ShowLetName sN TH.Name =>
172 InstrJoinable (ViewMachine sN) where
173 defJoin ln@(LetName n) j k = ViewMachine
174 { unViewMachine = \ct lm next ->
175 viewInstrCmd (Left n) ct lm
176 ("join", " "<>showLetName @sN n)
177 (unViewMachine j ct lm []) :
178 unViewMachine k (n:ct) lm next
180 } where gen = defJoin ln (viewGen j) (viewGen k)
181 refJoin ln@(LetName n) = ViewMachine
182 { unViewMachine = \ct lm next ->
183 viewInstrCmd (Right gen) ct lm ("refJoin", " "<>showLetName @sN n) [] : next
185 } where gen = refJoin ln
186 instance InstrInputable (ViewMachine sN) where
187 pushInput k = ViewMachine
188 { unViewMachine = \ct lm next ->
189 viewInstrCmd (Right gen) ct lm ("pushInput", "") [] :
190 unViewMachine k ct lm next
192 } where gen = pushInput (viewGen k)
193 loadInput k = ViewMachine
194 { unViewMachine = \ct lm next ->
195 viewInstrCmd (Right gen) ct lm ("loadInput", "") [] :
196 unViewMachine k ct lm next
198 } where gen = loadInput (viewGen k)
199 instance InstrReadable tok Gen => InstrReadable tok (ViewMachine sN) where
200 read es p k = ViewMachine
201 { unViewMachine = \ct lm next ->
202 viewInstrCmd (Right gen) ct lm ("read "<>showsPrec 10 p "", "") [] :
203 unViewMachine k ct lm next
205 } where gen = read es p (viewGen k)