本文介绍了使用ghc api获取重命名的(具有完全限定的导入)haskell AST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 限时删除!! 我可以使用ghc api来编译单个文件,我可以得到以下ghc编译器。我想获得haskell源代码的AST(所有函数调用完全限定)的重命名AST。 ghcmake = defaultErrorHandler defaultFatalMessager defaultFlushOut $ do runGhc(Just GP.libdir)$ do dflags< - getSessionDynFlags setSessionDynFlags dflags target< - guessTarget targetFile Nothing setTargets [target] load LoadAllTargets 从这个简单的演示中,重命名过程应该在load函数中完成。 源代码在这里 (file:///usr/local/haskell/ghc-7.10.2-x86_64/share/doc/ghc/html/libraries/ghc-7.10.2/src/GhcMake.html#load) p> load :: GhcMonad m => LoadHowMuch - > m SuccessFlag Source load :: GhcMonad m => LoadHowMuch - > m SuccessFlag load how_much = do mod_graph< - depanal [] False guessOutputFile hsc_env< - getSession let hpt1 = hsc_HPT hsc_env let dflags = hsc_dflags hsc_env - 坏引导模块是我们在模块图中具有 - B.hs-boot的模块,但没有B .hs - 下降扫描应确保不会发生 - (请参阅msDeps) let all_home_mods = [ms_mod_name s | s< - mod_graph,not(isBootSummary s)] bad_boot_mods = [s | s< - mod_graph,isBootSummary s, not(ms_mod_name s`elem` all_home_mods)] ASSERT(null bad_boot_mods)return() - 检查模块是否给出在HowMuch中实际存在,否则 - topSortModuleGraph将在稍后弹出。 让checkHowMuch(LoadUpTo m)= checkMod m checkHowMuch(LoadDependenciesOf m)= checkMod m checkHowMuch _ = id checkMod m and_then | m`elem` all_home_mods = and_then |否则= do liftIO $ errorMsg dflags(文本no such module:+ quotes(ppr m)) return失败 checkHowMuch how_much $ do - mg2_with_srcimps删除hi-boot节点,返回带循环的 - 图形。除此之外,它用于 - 在失败的 - upsweep之后取消部分完整的周期,并且从hpt中移除所有模块 - 没有严格向下关闭,在调用期间编译。 let mg2_with_srcimps :: [SCC ModSummary] mg2_with_srcimps = topSortModuleGraph True mod_graph Nothing - 如果我们可以确定任何{ - #SOURCE# - }汇入 - 肯定是不必要的,然后发出警告。 warnUnnecessarySourceImports mg2_with_srcimps let - 检查每个模块的稳定性属性。 stable_mods @(stable_obj,stable_bco) = checkStability hpt1 mg2_with_srcimps all_home_mods - 现在绝对多余的HPT的修剪位, - 节省空间。 pruned_hpt = pruneHomePackageTable hpt1 (flattenSCCs mg2_with_srcimps) stable_mods _< - liftIO $ evaluate pruned_hpt - 在我们卸载之前任何事情,请确保我们不会留下一个旧的交互式上下文,指向死锁绑定。此外, - 写修剪后的HPT以允许旧的HPT进行GC'd。 modifySession $ \_ - > discardIC $ hsc_env {hsc_HPT = pruned_hpt} liftIO $ debugTraceMsg dflags 2(文本Stable obj:< +> ppr stable_obj $$ textStable BCO:< + > ppr stable_bco) - 卸载将要重新链接的模块。 let stable_linkables = [linkable | m< - stable_obj ++ stable_bco,只是hmi< - [lookupUFM pruned_hpt m],只能链接< - [hm_linkable hmi]] liftIO $卸载hsc_env stable_linkables - 我们现在可以检测到没有被打破的周期 - 一个源代码导入,并立即投诉,但似乎更好 - 让upsweep_mods执行此操作,所以至少有一些有用的工作会在放弃上升之前完成。 --hPutStrLn stderr在tsort之后:\\\ --hPutStrLn stderr(showSDoc(vcat(map ppr mg2))) - 现在执行upsweep,为 - turn中的每个模块调用编译。最终结果是所有内容的第3版。 - 对模块图进行拓扑排序,这次包括hi-boot - 节点,并且可能只包括图中指定模块可到达的部分 - 在第二个参数中加载。 - 该图应该是无周期的。 - 如果我们限制图的一部分,我们 - 也想保留一切仍然稳定。 let full_mg :: [SCC ModSummary] full_mg = topSortModuleGraph False mod_graph Nothing maybe_top_mod = case how_much LoadUpTo m - >只需m LoadDependenciesOf m - >只需m - - > Nothing partial_mg0 :: [SCC ModSummary] partial_mg0 = topSortModuleGraph False mod_graph maybe_top_mod $ b - LoadDependenciesOf m:我们希望upsweep只停止 - 缺少指定的模块(除非指定的模块 - 稳定)。 partial_mg | LoadDependenciesOf _mod = ASSERT(的情况last partial_mg0)AcyclicSCC ms - > ms_mod_name ms == _mod; _ - > False) List.init partial_mg0 |否则 = partial_mg0 stable_mg = [AcyclicSCC ms | AcyclicSCC ms ms_mod_name ms`elem` stable_obj ++ stable_bco] - partial_mg中不稳定的模块 - NB。也保留周期,我们需要稍后发出错误消息 unstable_mg = filter not_stable partial_mg 其中not_stable(CyclicSCC _)= True not_stable(AcyclicSCC ms) = ms_mod_name ms` notElem` stable_obj ++ stable_bco - 在尝试加载 - 一个不稳定的模块(#7231)之前先加载所有稳定模块。 mg = stable_mg ++ unstable_mg - 编译之间的清理让清理hsc_env = intermediateCleanTempFiles(hsc_dflags hsc_env)(flattenSCCs mg2_with_srcimps) hsc_env liftIO $ debugTraceMsg dflags 2(挂起(文本准备上传) 2(ppr mg)) n_jobs< - case parMakeCount dflags of Nothing - > liftIO getNumProcessors 只需n - >返回n let upsweep_fn | n_jobs> 1 = parUpsweep n_jobs |否则= upsweep setSession hsc_env {hsc_HPT = emptyHomePackageTable} (upsweep_ok,modsUpswept) - Make modsDone是每个家庭模块的摘要现在 - 可用;这应该等于hpt3的域。 - 进入一个大概顶部的底部顺序(因此反转)。 让modsDone =反向modsUpswept - 尝试并以某种形式进行链接,具体取决于 - upsweep是完全还是部分成功。 如果成功upsweep_ok 然后 - 简单;只是重新链接一切。 做liftIO $ debugTraceMsg dflags 2(文字Upsweep complete successful。) - 自行清理 hsc_env1< - getSession liftIO $ intermediateCleanTempFiles dflags modsDone hsc_env1 - 在用户 - 表示'-o foo'但我们不打算进行任何链接的混乱情况下发出警告。 - 如果(a)其中一个模块是 - 称为Main,或者(b)用户说的是-no-hs-main,表示 - 我们尝试链接main()将会从其他地方来。 - let of = outputFile dflags let no_hs_main = gopt Opt_NoHsMain dflags let main_mod = mainModIs dflags a_root_is_Main = any((== main_mod ).ms_mod)mod_graph do_linking = a_root_is_Main || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib 当(ghcLink dflags == LinkBinary &&&&&&;&只是ofile&&&不是do_linking)$ liftIO $ debugTraceMsg dflags 1 $ text(警告:输出被重定向为-o,++ 但不会生成输出结果\\\++ ,因为没有++ ) $ b $ - 将所有内容链接在一起$ b $ linkresult< - liftIO $ link(ghcLink dflags)dflags do_linking(hsc_HPT hsc_env1)(moduleName main_mod)++module loadFinish成功的结果 上面的代码片断检查模块依赖性是否正常,它似乎直接跳转到链接?我找不到 link 函数的位置。 linkresult< - liftIO $ link ghcLink dflags)dflags do_linking(hsc_HPT hsc_env1) loadFinish成功的结果 相关帖子: https://mistuke.wordpress .com / category / vsx / 解决方案 From: https://wiki.haskell.org/GHC/As_a_library#Another_example ghcmake = defaultErrorHandler defaultFatalMessager defaultFlushOut $ do runGhc(Just GP.libdir)$ do dflags< - getSessionDynFlags setSessionDynFlags dflags target< - guessTarget targetFile Nothing setTargets [target] load LoadAllTargets modSum< - getModSummary $ mkModuleName<您的模块名称此处>中p t let(Just renamedSource)= tm_renamed_source t I can get the following ghc compiler working using ghc api to compile a single file.I would like to get the renamed AST of haskell source (AST with all function calls fully qualified)ghcmake = defaultErrorHandler defaultFatalMessager defaultFlushOut $ do runGhc (Just GP.libdir) $ do dflags <- getSessionDynFlags setSessionDynFlags dflags target <- guessTarget targetFile Nothing setTargets [target] load LoadAllTargetsFrom this simple demo,the renaming process ought be done in "load" function.the source is here(file:///usr/local/haskell/ghc-7.10.2-x86_64/share/doc/ghc/html/libraries/ghc-7.10.2/src/GhcMake.html#load)load :: GhcMonad m => LoadHowMuch -> m SuccessFlag Sourceload :: GhcMonad m => LoadHowMuch -> m SuccessFlagload how_much = do mod_graph <- depanal [] False guessOutputFile hsc_env <- getSession let hpt1 = hsc_HPT hsc_env let dflags = hsc_dflags hsc_env -- The "bad" boot modules are the ones for which we have -- B.hs-boot in the module graph, but no B.hs -- The downsweep should have ensured this does not happen -- (see msDeps) let all_home_mods = [ms_mod_name s | s <- mod_graph, not (isBootSummary s)] bad_boot_mods = [s | s <- mod_graph, isBootSummary s, not (ms_mod_name s `elem` all_home_mods)] ASSERT( null bad_boot_mods ) return () -- check that the module given in HowMuch actually exists, otherwise -- topSortModuleGraph will bomb later. let checkHowMuch (LoadUpTo m) = checkMod m checkHowMuch (LoadDependenciesOf m) = checkMod m checkHowMuch _ = id checkMod m and_then | m `elem` all_home_mods = and_then | otherwise = do liftIO $ errorMsg dflags (text "no such module:" <+> quotes (ppr m)) return Failed checkHowMuch how_much $ do -- mg2_with_srcimps drops the hi-boot nodes, returning a -- graph with cycles. Among other things, it is used for -- backing out partially complete cycles following a failed -- upsweep, and for removing from hpt all the modules -- not in strict downwards closure, during calls to compile. let mg2_with_srcimps :: [SCC ModSummary] mg2_with_srcimps = topSortModuleGraph True mod_graph Nothing -- If we can determine that any of the {-# SOURCE #-} imports -- are definitely unnecessary, then emit a warning. warnUnnecessarySourceImports mg2_with_srcimps let -- check the stability property for each module. stable_mods@(stable_obj,stable_bco) = checkStability hpt1 mg2_with_srcimps all_home_mods -- prune bits of the HPT which are definitely redundant now, -- to save space. pruned_hpt = pruneHomePackageTable hpt1 (flattenSCCs mg2_with_srcimps) stable_mods _ <- liftIO $ evaluate pruned_hpt -- before we unload anything, make sure we don't leave an old -- interactive context around pointing to dead bindings. Also, -- write the pruned HPT to allow the old HPT to be GC'd. modifySession $ \_ -> discardIC $ hsc_env { hsc_HPT = pruned_hpt } liftIO $ debugTraceMsg dflags 2 (text "Stable obj:" <+> ppr stable_obj $$ text "Stable BCO:" <+> ppr stable_bco) -- Unload any modules which are going to be re-linked this time around. let stable_linkables = [ linkable | m <- stable_obj++stable_bco, Just hmi <- [lookupUFM pruned_hpt m], Just linkable <- [hm_linkable hmi] ] liftIO $ unload hsc_env stable_linkables -- We could at this point detect cycles which aren't broken by -- a source-import, and complain immediately, but it seems better -- to let upsweep_mods do this, so at least some useful work gets -- done before the upsweep is abandoned. --hPutStrLn stderr "after tsort:\n" --hPutStrLn stderr (showSDoc (vcat (map ppr mg2))) -- Now do the upsweep, calling compile for each module in -- turn. Final result is version 3 of everything. -- Topologically sort the module graph, this time including hi-boot -- nodes, and possibly just including the portion of the graph -- reachable from the module specified in the 2nd argument to load. -- This graph should be cycle-free. -- If we're restricting the upsweep to a portion of the graph, we -- also want to retain everything that is still stable. let full_mg :: [SCC ModSummary] full_mg = topSortModuleGraph False mod_graph Nothing maybe_top_mod = case how_much of LoadUpTo m -> Just m LoadDependenciesOf m -> Just m _ -> Nothing partial_mg0 :: [SCC ModSummary] partial_mg0 = topSortModuleGraph False mod_graph maybe_top_mod -- LoadDependenciesOf m: we want the upsweep to stop just -- short of the specified module (unless the specified module -- is stable). partial_mg | LoadDependenciesOf _mod <- how_much = ASSERT( case last partial_mg0 of AcyclicSCC ms -> ms_mod_name ms == _mod; _ -> False ) List.init partial_mg0 | otherwise = partial_mg0 stable_mg = [ AcyclicSCC ms | AcyclicSCC ms <- full_mg, ms_mod_name ms `elem` stable_obj++stable_bco ] -- the modules from partial_mg that are not also stable -- NB. also keep cycles, we need to emit an error message later unstable_mg = filter not_stable partial_mg where not_stable (CyclicSCC _) = True not_stable (AcyclicSCC ms) = ms_mod_name ms `notElem` stable_obj++stable_bco -- Load all the stable modules first, before attempting to load -- an unstable module (#7231). mg = stable_mg ++ unstable_mg -- clean up between compilations let cleanup hsc_env = intermediateCleanTempFiles (hsc_dflags hsc_env) (flattenSCCs mg2_with_srcimps) hsc_env liftIO $ debugTraceMsg dflags 2 (hang (text "Ready for upsweep") 2 (ppr mg)) n_jobs <- case parMakeCount dflags of Nothing -> liftIO getNumProcessors Just n -> return n let upsweep_fn | n_jobs > 1 = parUpsweep n_jobs | otherwise = upsweep setSession hsc_env{ hsc_HPT = emptyHomePackageTable } (upsweep_ok, modsUpswept) <- upsweep_fn pruned_hpt stable_mods cleanup mg -- Make modsDone be the summaries for each home module now -- available; this should equal the domain of hpt3. -- Get in in a roughly top .. bottom order (hence reverse). let modsDone = reverse modsUpswept -- Try and do linking in some form, depending on whether the -- upsweep was completely or only partially successful. if succeeded upsweep_ok then -- Easy; just relink it all. do liftIO $ debugTraceMsg dflags 2 (text "Upsweep completely successful.") -- Clean up after ourselves hsc_env1 <- getSession liftIO $ intermediateCleanTempFiles dflags modsDone hsc_env1 -- Issue a warning for the confusing case where the user -- said '-o foo' but we're not going to do any linking. -- We attempt linking if either (a) one of the modules is -- called Main, or (b) the user said -no-hs-main, indicating -- that main() is going to come from somewhere else. -- let ofile = outputFile dflags let no_hs_main = gopt Opt_NoHsMain dflags let main_mod = mainModIs dflags a_root_is_Main = any ((==main_mod).ms_mod) mod_graph do_linking = a_root_is_Main || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib when (ghcLink dflags == LinkBinary && isJust ofile && not do_linking) $ liftIO $ debugTraceMsg dflags 1 $ text ("Warning: output was redirected with -o, " ++ "but no output will be generated\n" ++ "because there is no " ++ moduleNameString (moduleName main_mod) ++ " module.") -- link everything together linkresult <- liftIO $ link (ghcLink dflags) dflags do_linking (hsc_HPT hsc_env1) loadFinish Succeeded linkresultThe code snippet above checks that the module dependency is ok,but after that it seems to jump directly to linking?? and i can not find where the link function is.linkresult <- liftIO $ link (ghcLink dflags) dflags do_linking (hsc_HPT hsc_env1) loadFinish Succeeded linkresultrelevant posts:https://mistuke.wordpress.com/category/vsx/ 解决方案 From: https://wiki.haskell.org/GHC/As_a_library#Another_exampleghcmake = defaultErrorHandler defaultFatalMessager defaultFlushOut $ do runGhc (Just GP.libdir) $ do dflags <- getSessionDynFlags setSessionDynFlags dflags target <- guessTarget targetFile Nothing setTargets [target] load LoadAllTargets modSum <- getModSummary $ mkModuleName "<Your module name here>" p <- parseModule modSum t <- typecheckModule p let (Just renamedSource) = tm_renamed_source tAfter your example code you need to get the module summary for the module you want to parse. Then you need to actually run the parser and the typechecker. Finally you can retrieve the renamed AST from the typechecked result. 这篇关于使用ghc api获取重命名的(具有完全限定的导入)haskell AST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 1403页,肝出来的.. 09-09 02:00