提取Haskell源代码的STG

6
我正在尝试通过Outputable从Haskell源代码中提取STG表示作为String,但似乎coreToStgArgs出现以下转储信息时会发生错误:
user@machine ~/Desktop/hue $ runhaskell test.hs 
[foo :: forall a. Num a => a -> a
 [GblId, Arity=2, Caf=NoCafRefs, Str=DmdType] =
     \r srt:SRT:[] [$dNum a1] + $dNum a1 a1;,
 bar :: Int -> Int
 [GblId,test.hs: test.hs: panic! (the 'impossible' happened)
  (GHC version 7.10.3 for x86_64-unknown-linux):
    coreToStgArgs I# 3

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

这里有一个名为 FooBar.hs 的文件,我想要提取它:

module FooBar where

foo a = a + a

bar :: Int -> Int
bar b = b + 3

这是我使用的 test.hs 的源代码:

import CoreToStg
import GHC
import GHC.Paths
import Outputable
import StgSyn

mkDynFlags :: IO DynFlags
mkDynFlags = runGhc (Just libdir) getSessionDynFlags

mkSTG :: FilePath -> FilePath -> IO [StgBinding]
mkSTG proj src = do
    dflags  <- mkDynFlags
    ghc_core <- runGhc (Just libdir) $ do
        setSessionDynFlags (dflags {importPaths = [proj]})
        compileToCoreSimplified src
        -- compileToCoreModule src
    coreToStg dflags (cm_module ghc_core) (cm_binds ghc_core)

mkIOStr :: (Outputable a) => a -> IO String
mkIOStr obj = do
    dflags <- mkDynFlags
    let ppr_str = showPpr dflags obj
    return ppr_str

main :: IO ()
main = do
    let proj = "/home/user/Desktop/hue"
    let src  = proj ++ "/FooBar.hs"
    res <- mkIOStr =<< mkSTG proj src
    putStrLn res

看起来有人在我之前几年遇到了类似的问题:

https://ghc.haskell.org/trac/ghc/ticket/7159

然而,我不知道之后发生了什么。我也不确定这是否是从任意Haskell源代码中提取STG的正确方法,如果有更好的替代方案可行,我想听听它们的建议。
编辑:对于以下程序,STG翻译似乎成功了,其中bar b = b + 3被改为bar b = 3
module FooBar where

foo a = a + a

bar :: Int -> Int
bar b = 3

事实上,乍一看,如果诱导的Core Haskell不强制执行原始操作,事情似乎是有效的。例如,bar b = 3 + 9失败了。

1
你链接的错误说:“*这其实不是一个错误。在尝试使用CoreToStg.coreToStg之前,我需要使用CorePrep.corePrepPgm*”。 - melpomene
啊,经过一些努力终于成功了 :)谢谢! - Anton Xue
你应该将可运行的代码作为答案发布。 - melpomene
1个回答

1
感谢melpomene指出文档中我忽略的内容。
这里是已修改的test.hs源码,现在可以正常运行:
import CorePrep
import CoreToStg
import GHC
import GHC.Paths
import GhcMonad
import HscTypes
import Outputable
import StgSyn
import System.IO

mkSTG :: FilePath -> FilePath -> IO [StgBinding]
mkSTG proj src = runGhc (Just libdir) $ do
        env    <- getSession
        dflags <- getSessionDynFlags
        setSessionDynFlags (dflags {importPaths = [proj]})
        target <- guessTarget src Nothing
        setTargets [target]
        load LoadAllTargets

        mod_graph <- getModuleGraph
        let mod_sum = head mod_graph  -- This is bad practice
        pmod <- parseModule mod_sum
        tmod <- typecheckModule pmod
        dmod <- desugarModule tmod
        let guts  = coreModule dmod
        let loc   = ms_location mod_sum
        let binds = mg_binds guts
        let tcs   = mg_tcs guts
        prep <- liftIO $ corePrepPgm env loc binds tcs
        liftIO $ coreToStg dflags (mg_module guts) prep

mkIOStr :: (Outputable a) => a -> IO String
mkIOStr obj = do
    dflags <- runGhc (Just libdir) getSessionDynFlags
    let ppr_str = showPpr dflags obj
    return ppr_str

main :: IO ()
main = do
    let proj = "/home/celery/Desktop/hue"
    let src  = proj ++ "/FooBar.hs"
    res <- mkIOStr =<< mkSTG proj src
    putStrLn res

我不确定从Target中恢复ModSummary(因此也是ModuleName)的最佳方法是什么,但我依稀记得它是ModuleGraph的第一个元素,ModuleGraph定义为type ModuleGraph = [ModSummary]corePrepPgm的类型签名在GHC 7和8之间也有所不同:

https://downloads.haskell.org/~ghc/7.10.1/docs/html/libraries/ghc-7.10.1/CorePrep.html

https://downloads.haskell.org/~ghc/latest/docs/html/libraries/ghc-8.0.1/CorePrep.html

欢迎提出改进意见 :)
编辑:我发现了反例——ModuleGraphhead并不总是目标。我的当前解决方法是查看ModuleGraph中是否有任何ModSummary包含与初始源文件位置匹配的位置。

“--这是不好的做法”-确实如此,但GHC API充满了历史意外(例如用“[]”类型表示非空列表),有时基本上迫使您做“坏”事情。所以不要对此感到太糟糕! - user2407038

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接