{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE UndecidableInstances #-} -- For ShowLetName module Symantic.Parser.Machine.View where import Data.Bool (Bool(..)) import Data.Either (Either(..)) import Data.Function (($), (.), id, on) import Data.Functor ((<$>)) import Data.Kind (Type) import Data.Ord (Ord(..)) import Data.Semigroup (Semigroup(..)) import Data.String (String) import Data.Tuple (fst) import Text.Show (Show(..)) import qualified Data.HashMap.Strict as HM import qualified Data.List as List import qualified Data.Map.Strict as Map import qualified Data.Set as Set import qualified Data.Tree as Tree import qualified Language.Haskell.TH.Syntax as TH import Prelude (error) import Symantic.Parser.Grammar.ObserveSharing (ShowLetName(..)) import Symantic.Parser.Machine.Instructions import Symantic.Typed.ObserveSharing (SomeLet(..)) import Symantic.Parser.Machine.Generate -- * Type 'ViewMachine' data ViewMachine (showName::Bool) inp (vs:: [Type]) a = ViewMachine { viewGen :: Gen inp vs a -- ^ Provide 'GenAnalysis', which next important for debugging -- and improving golden tests, see 'viewInstrCmd'. , unViewMachine :: CallTrace -> LetMap GenAnalysis -> -- Output of 'runGenAnalysis'. Tree.Forest (String, String) -> Tree.Forest (String, String) } viewMachine :: ViewMachine sN inp vs a -> ViewMachine sN inp vs a viewMachine = id -- | Helper to view a command. viewInstrCmd :: Either TH.Name (Gen inp vs a) -> CallTrace -> LetMap GenAnalysis -> (String, String) -> Tree.Forest (String, String) -> Tree.Tree (String, String) viewInstrCmd gen ct lm (n, no) = Tree.Node $ (n <> "\nminReads="<>showsPrec 11 (minReads ga) "" <> "\nmayRaise="<>showsPrec 11 (Map.keys (mayRaise ga)) "" , no) where ga = case gen of Right r -> (\f -> f ct) $ genAnalysis r $ (\f _ct -> f) <$> lm Left l -> HM.findWithDefault (error (show (l, HM.keys lm))) l lm -- | Helper to view an argument. viewInstrArg :: String -> Tree.Forest (String, String) -> Tree.Tree (String, String) viewInstrArg n = Tree.Node $ ("<"<>n<>">", "") instance Show (ViewMachine sN inp vs a) where show vm = List.unlines $ drawTrees $ unViewMachine vm [] (runGenAnalysis (genAnalysisByLet (viewGen vm))) [] where draw :: Tree.Tree (String, String) -> [String] draw (Tree.Node (x, n) ts0) = shift "" " " (List.zipWith (<>) (List.lines x) (n : List.repeat "")) <> shift "| " "| " (drawTrees ts0) drawTrees [] = [] drawTrees [t] = draw t drawTrees (t:ts) = draw t <> drawTrees ts shift ind0 ind = List.zipWith (<>) (ind0 : List.repeat ind) instance InstrValuable (ViewMachine sN) where pushValue a k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("pushValue "<>showsPrec 10 a "", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = pushValue a (viewGen k) popValue k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("popValue", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = popValue (viewGen k) lift2Value f k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("lift2Value "<>showsPrec 10 f "", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = lift2Value f (viewGen k) swapValue k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("swapValue", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = swapValue (viewGen k) instance InstrExceptionable (ViewMachine sN) where raise exn = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("raise "<>show exn, "") [] : next , viewGen = gen } where gen = raise exn fail flr = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("fail "<>show (Set.toList flr), "") [] : next , viewGen = gen } where gen = fail flr commit exn k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("commit "<>show exn, "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = commit exn (viewGen k) catch exn ok ko = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("catch "<>show exn, "") [ viewInstrArg "ok" (unViewMachine ok ct lm []) , viewInstrArg "ko" (unViewMachine ko ct lm []) ] : next , viewGen = gen } where gen = catch exn (viewGen ok) (viewGen ko) instance InstrBranchable (ViewMachine sN) where caseBranch l r = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("case", "") [ viewInstrArg "left" (unViewMachine l ct lm []) , viewInstrArg "right" (unViewMachine r ct lm []) ] : next , viewGen = gen } where gen = caseBranch (viewGen l) (viewGen r) choicesBranch ps bs d = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("choicesBranch "<>show ps, "") ( ((\b -> viewInstrArg "branch" $ unViewMachine b ct lm []) <$> bs) <> [ viewInstrArg "default" (unViewMachine d ct lm []) ] ) : next , viewGen = gen } where gen = choicesBranch ps (viewGen <$> bs) (viewGen d) instance ShowLetName sN TH.Name => InstrCallable (ViewMachine sN) where defLet defs k = ViewMachine { unViewMachine = \ct lm next -> (<> unViewMachine k ct lm next) $ List.sortBy (compare `on` (((fst <$>) <$>) . Tree.levels)) $ ((\(n, SomeLet sub) -> viewInstrCmd (Left n) ct lm ("let", " "<>showLetName @sN n) (unViewMachine sub ct lm [])) <$> HM.toList defs) , viewGen = gen } where gen = defLet ((\(SomeLet x) -> SomeLet (viewGen x)) <$> defs) (viewGen k) jump ln@(LetName n) = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("jump", " "<>showLetName @sN n) [] : next , viewGen = gen } where gen = jump ln call ln@(LetName n) k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("call", " "<>showLetName @sN n) [] : unViewMachine k (n:ct) lm next , viewGen = gen } where gen = call ln (viewGen k) ret = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("ret", "") [] : next , viewGen = gen } where gen = ret instance ShowLetName sN TH.Name => InstrJoinable (ViewMachine sN) where defJoin ln@(LetName n) j k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Left n) ct lm ("join", " "<>showLetName @sN n) (unViewMachine j ct lm []) : unViewMachine k (n:ct) lm next , viewGen = gen } where gen = defJoin ln (viewGen j) (viewGen k) refJoin ln@(LetName n) = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("refJoin", " "<>showLetName @sN n) [] : next , viewGen = gen } where gen = refJoin ln instance InstrInputable (ViewMachine sN) where pushInput k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("pushInput", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = pushInput (viewGen k) loadInput k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("loadInput", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = loadInput (viewGen k) instance InstrReadable tok Gen => InstrReadable tok (ViewMachine sN) where read es p k = ViewMachine { unViewMachine = \ct lm next -> viewInstrCmd (Right gen) ct lm ("read "<>showsPrec 10 p "", "") [] : unViewMachine k ct lm next , viewGen = gen } where gen = read es p (viewGen k)