Как проверить плагины GHC? - PullRequest
13 голосов
/ 27 апреля 2019

Последние версии GHC имеют новую функцию «плагинов», в которой вы можете написать обычный код на Haskell, скомпилировать его как обычно, а затем вставить в компилятор, чтобы он мог работать с внутренним состоянием GHC.

Который очень круто.Однако есть небольшая загвоздка: чтобы сделать это, плагин должен быть уже скомпилирован (кажется очевидным) и зарегистрирован как пакет в БД пакета!

Хорошо, еслиплагин закончен;упакуйте его и положите на Hackage для всех желающих.Но как обойти это, пытаясь разработать пакет?Как работает ваш цикл edit-compile-execute, когда при каждом редактировании вам приходится вручную отменять регистрацию старого пакета, создавать новый и регистрировать его?

В принципе, есть ли какой-то способ, которым я могу обойтисьэто требование при попытке разработки плагина?

1 Ответ

4 голосов
/ 28 апреля 2019

Если вы используете Cabal, он должен управлять всем за вас:

my-plugin.cabal
cabal-version: 2.4
name: my-plugin
version: 1.0.0.0

library
  build-depends: base ^>= 4.12.0.0
               , ghc ^>= 8.6.1
  hs-source-dirs: src
  exposed-modules: MyPlugin

-- could also be an internal library, executable, etc
test-suite test-plugin
  type: exitcode-stdio-1.0
  -- the dependency on my-plugin is everything, placing it
  -- in the package DB of the GHC compiling this test
  build-depends: base, my-plugin
  hs-source-dirs: test
  ghc-options: -fplugin=MyPlugin
  main-is: Main.hs
src/MyPlugin.hs
module MyPlugin(plugin) where
import GhcPlugins
-- this is an example plugin from the manual
-- it prints the names of the non-recursive bindings in each module

plugin :: Plugin
plugin = defaultPlugin {
  installCoreToDos = install
  }

install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install _ todo = do
  return (CoreDoPluginPass "Say name" pass : todo)

pass :: ModGuts -> CoreM ModGuts
pass guts = do dflags <- getDynFlags
               bindsOnlyPass (mapM (printBind dflags)) guts
  where printBind :: DynFlags -> CoreBind -> CoreM CoreBind
        printBind dflags bndr@(NonRec b _) = do
          putMsgS $ "Non-recursive binding named " ++ showSDoc dflags (ppr b)
          return bndr
        printBind _ bndr = return bndr
test/Main.hs
module Main where
import Numeric.Natural
import Prelude hiding (even, odd)

-- printed
x :: Int
x = 5

-- not printed
fixObvious :: (a -> a) -> a
fixObvious f = f (fixObvious f)

-- printed
fixSubtle :: (a -> a) -> a
fixSubtle f = let x = f x in x

-- neither printed
even, odd :: Natural -> Bool
even 0 = True
even n = odd (n - 1)
odd 0 = False
odd n = even (n - 1)

-- printed
main :: IO ()
main = return ()
-- if the plugin were more interesting, you may want to test that any
-- modified definitions act like you expect them to
...