packages feed

haskell-names 0.2 → 0.2.1

raw patch · 5 files changed

+337/−9 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Language.Haskell.Names.Interfaces: instance FromJSON l0 => FromJSON (Assoc l0)
- Language.Haskell.Names.Interfaces: instance ToJSON l0 => ToJSON (Assoc l0)
+ Language.Haskell.Names.Interfaces: instance FromJSON (Assoc ())
+ Language.Haskell.Names.Interfaces: instance ToJSON (Assoc ())

Files

+ CHANGELOG.md view
@@ -0,0 +1,28 @@+Changes+=======++Version 0.2.1+-------------++* Fix a bug where global symbols were annotated as local+* Make the code compile with aeson-0.6.2.0++Version 0.2+-------------++* Proper annotations for types and binding sites. `NameContext` now has a few+  new constructors.+* Properly support n+k patterns+* Expose the `Alg` datatype for open name resolution+* Expose the `HasOrigName` class++Version 0.1.2+-------------++Restore compatibility with Cabal 1.16++Version 0.1.1+-------------++Dummy release to force rebuild on hackage (now that haskell-src-exts 1.14 is+released).
+ README.md view
@@ -0,0 +1,272 @@+haskell-names+=============++haskell-names does name and module resolution for haskell-src-exts AST.++Namely, it can do the following:++* for a module, compute its interface, i.e. the set of entities exported by the+  module, together with their original names.+* for each name in the module, figure out what it refers to — whether it's bound+  locally (say, by a `where` clause) or globally (and then give its origin).++Installation+------------++To install a released version:++1. Install Cabal and cabal-install from [our git repository][cabal]+2. `cabal install haskell-names hs-gen-iface`++If you're building a development version, then you might also need to install+development versions of [haskell-src-exts][hse], [haskell-packages][hp], and [hse-cpp][].++[cabal]: https://github.com/feuerbach/Cabal+[hse]: https://github.com/haskell-suite/haskell-src-exts+[hp]: https://github.com/haskell-suite/haskell-packages+[hse-cpp]: https://github.com/haskell-suite/hse-cpp++Module interfaces+-----------------++`hs-gen-iface` is a «compiler» that generates interfaces for Haskell modules.++An interface is a JSON file that lists all entities (types, classes, functions+etc.) exported by every module. For example, here are a couple of entries from+`Prelude.names`:++``` json+[+  {+    "fixity": null,+    "origin": {+      "name": "map",+      "module": "GHC.Base",+      "package": "base-4.7.0.0"+    },+    "entity": "value"+  },+  {+    "fixity": null,+    "origin": {+      "name": "IO",+      "module": "GHC.Types",+      "package": "ghc-prim-0.3.1.0"+    },+    "entity": "data"+  },+  ...+]+```++As you see, each entity is annotated with the module and package where it was+originally defined, and also with its fixity. Additionally, class methods, field+selectors, and data constructors are annotated with the class or type they+belong to.++### Generating interfaces++Thanks to haskell-packages, `hs-gen-iface` is fully integrated with Cabal. To+produce and install interface files, pass `--haskell-suite -w hs-gen-iface` flags+to `cabal install`, for instance++    cabal install --haskell-suite -w hs-gen-iface mtl++This assumes that the `hs-gen-iface` executable is in your `PATH`. You can specify+the full path to `hs-gen-iface` after `-w`, too.++#### Core packages++haskell-names comes with the global package database populated with some core+packages:++    % hs-gen-iface pkg list --global+    base-4.7.0.0+    ghc-prim-0.3.1.0+    integer-simple-0.1.1.0++#### Compiling core packages by hand++Suppose you need to compile any of the core packages by hand — for example, to+get a different version than the one bundled with haskell-names.++Core packages, such as `ghc-prim`, `integer-simple`, and `base`, are highly+GHC-specific and need to be tweaked a bit before they can be processed by+haskell-names. Get our modified versions:++* [ghc-prim](https://github.com/haskell-suite/ghc-prim)+* [base](https://github.com/haskell-suite/base)+* [integer-simple](https://github.com/haskell-suite/integer-simple)++Note that Cabal's new dependency solver won't let you install `ghc-prim`+or `base` easily. There are two ways to work around this:++1. Use the old solver:++        cabal install --haskell-suite -w hs-gen-iface --solver=topdown++2. Invoke all the steps manually:++        cabal configure --haskell-suite -w hs-gen-iface+        cabal build+        cabal install --only++### Using interfaces++You can parse interface files directly, but a better idea is to use+`Distribution.HaskellSuite.Packages` API (from haskell-packages), combined with+the package database `NamesDB` defined in `Language.Haskell.Modules.Interfaces`.++Name resolution+---------------++There are two approaches to name resolution.++A simpler one is provided by the `annotateModule` function which annotates the+module with scoping information.++A more advanced interface is given by the `Language.Haskell.Names.Open` module.+Its essence is described in the article [Open your name resolution][openrec].+It is, however, very experimental.++[openrec]: http://ro-che.info/articles/2013-03-04-open-name-resolution.html++### Example++Let's say you have a module and you want to find out whether it uses+`Prelude.head`.++``` haskell+import Language.Haskell.Exts.Annotated+import Language.Haskell.Names+import Language.Haskell.Names.Interfaces+import Distribution.HaskellSuite+import Distribution.Simple.Compiler++import Data.Maybe+import Data.List+import Data.Proxy+import qualified Data.Set as Set+import qualified Data.Foldable as Foldable+import Text.Printf+import Control.Applicative+import Control.Monad++main = do++  -- read the program's source from stdin+  source <- getContents++  let+    -- parse the program (using haskell-src-exts)+    ast = fromParseResult $+      parseModuleWithMode defaultParseMode {parseFilename="stdin"} source++  -- get all installed packages (user and global)+  pkgs <-+    (++) <$>+      getInstalledPackages (Proxy :: Proxy NamesDB) UserPackageDB <*>+      getInstalledPackages (Proxy :: Proxy NamesDB) GlobalPackageDB++  headUsages <- evalNamesModuleT (findHeads ast) pkgs++  forM_ headUsages $ \loc ->+    printf "Prelude.head is used at %s\n" (prettyPrint $ srcInfoSpan loc)++  when (null headUsages) $+    printf "Congratulations! Your code doesn't use Prelude.head\n"++-- this is a computation in a ModuleT monad, because we need access to+-- modules' interfaces+findHeads :: Module SrcSpanInfo -> ModuleT Symbols IO [SrcSpanInfo]+findHeads ast = do+  -- first of all, figure out the canonical name of "Prelude.head"+  -- (hint: it's "GHC.List.head")+  Symbols values _types <- fromMaybe (error "Prelude not found") <$> getModuleInfo "Prelude"+  let+    headOrigName =+      fromMaybe (error "Prelude.head not found") $+      listToMaybe+        -- this looks a bit scary, but we're just walking through all+        -- values defined in Prelude and looking for one with unqualified+        -- name "head"+        [ origName+        | SymValue { sv_origName = origName@(OrigName _pkg (GName _mod "head")) } <- Set.toList values+        ]+  +  -- annotate our ast with name binding information+  annotatedAst <-+    annotateModule+      Haskell2010 -- base language+      []          -- set of extensions+      ast++  +  let+    -- get list of all annotations+    annotations = Foldable.toList annotatedAst++    -- look for headOrigName+    headUsages = nub+      [ location+      | Scoped (GlobalValue valueInfo) location <- annotations +      , sv_origName valueInfo == headOrigName+      ]++  return headUsages+```++#### Example invocation+++    % ./find-heads +    one = head [1]+    ^D+    Prelude.head is used at stdin: (1:7) - (1:11)++    % ./find-heads+    import Prelude hiding (head)+    import Data.Text++    f = head (pack "foo")+    ^D+    Congratulations! Your code doesn't use Prelude.head++### API documentation++See [haskell-names haddock documentation][doc-index].++The two modules you need are:++* [Language.Haskell.Names][] — exports the core functions and data types+* [Language.Haskell.Names.Interfaces][] — lets you work with haskell-names interface files++Other modules are more experimental, less documented, and you probably don't need+them anyway.++[doc-index]: http://haskell-suite.github.io/docs/haskell-names/+[Language.haskell.Names]: http://haskell-suite.github.io/docs/haskell-names/Language-Haskell-Names.html+[Language.Haskell.Names.Interfaces]: http://haskell-suite.github.io/docs/haskell-names/Language-Haskell-Names-Interfaces.html++### Known issues++See the [list of all issues][issues].++* Because a non-trivial amount of packages are not designed to work with+  anything except GHC, hs-gen-iface currently pretends to be GHC. This is of+  course not acceptable — contributions here are welcome. ([#32][])+* haskell-names doesn't perform validation yet. If a module is not valid+  Haskell, then the behaviour is undefined. See the issues marked as+  [validation][].+* Symbol fixities are not recorded ([#1][])+* Type variables are not resolved ([#2][])+* Arrows are not fully supported ([#8][])+* Type/data families and associated types are not fully supported ([#25][])++[issues]: https://github.com/haskell-suite/haskell-names/issues/+[#1]: https://github.com/haskell-suite/haskell-names/issues/1+[#2]: https://github.com/haskell-suite/haskell-names/issues/2+[#8]: https://github.com/haskell-suite/haskell-names/issues/8+[#25]: https://github.com/haskell-suite/haskell-names/issues/25+[#32]: https://github.com/haskell-suite/haskell-names/issues/32+[validation]: https://github.com/haskell-suite/haskell-names/issues?labels=validation&page=1&state=open
haskell-names.cabal view
@@ -1,5 +1,5 @@ Name:                   haskell-names-Version:                0.2+Version:                0.2.1 License:                BSD3 Author:                 Roman Cheplyaka, Lennart Augustsson Maintainer:             Roman Cheplyaka <roma@ro-che.info>@@ -13,6 +13,9 @@ Build-Type:             Simple Cabal-Version:          >= 1.10 +extra-source-files:+  README.md+  CHANGELOG.md data-files:   libraries/integer-simple-0.1.1.0/GHC/Integer/Logarithms/Internals.names   libraries/integer-simple-0.1.1.0/GHC/Integer/Simple/Internals.names@@ -232,7 +235,7 @@ source-repository this   type:     git   location: git://github.com/haskell-suite/haskell-names.git-  tag:      v0.2+  tag:      v0.2.1  Library   Default-Language: Haskell2010
src/Language/Haskell/Names/Interfaces.hs view
@@ -1,5 +1,5 @@ -- | Reading 'Symbols' from and writing to interface files-{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-name-shadowing #-} module Language.Haskell.Names.Interfaces   (@@ -18,7 +18,6 @@ import Language.Haskell.Exts.Annotated import qualified Data.ByteString.Lazy as BS import Data.Aeson-import Data.Aeson.TH import Data.Monoid import Data.Char import Data.Typeable@@ -143,8 +142,27 @@    parseJSON _ = mzero --- FIXME-deriveJSON id ''Assoc+instance ToJSON (Assoc ()) where+  toJSON assoc =+    let+      (assocStr, prec) =+        case assoc of+          AssocNone prec  -> ("none", prec)+          AssocLeft prec  -> ("left", prec)+          AssocRight prec -> ("right", prec)+    in+      object ["fixity" .= toJSON (assocStr :: String), "precedence" .= toJSON prec]++instance FromJSON (Assoc ()) where+  parseJSON (Object v) = do+    fixity <- v .: "fixity"+    prec   <- v .: "precedence"+    case fixity :: String of+      "none"  -> return $ AssocNone prec+      "left"  -> return $ AssocLeft prec+      "right" -> return $ AssocRight prec+      _ -> mzero+  parseJSON _ = mzero  instance ToJSON Symbols where   toJSON (Symbols vals types) =
src/Language/Haskell/Names/Open/Instances.hs view
@@ -34,17 +34,24 @@ instance (Resolvable l, SrcInfo l, D.Data l) => Resolvable (Decl l) where   rtraverse e sc =     case e of+      -- N.B. We do not add pat to the local scope.+      --+      -- If this is a top-level binding, then we shouldn't do so, lest+      -- global values are marked as local.+      -- (see https://github.com/haskell-suite/haskell-names/issues/35)+      --+      -- If this is a local binding, then we have already introduced these+      -- variables when processing the enclosing Binds.       PatBind l pat mbType rhs mbWhere ->         let-          scWithPat = intro pat sc-          scWithWhere = intro mbWhere scWithPat+          scWithWhere = intro mbWhere sc         in         c PatBind           <| sc                -: l           <| sc                -: pat           <| sc                -: mbType           <| exprV scWithWhere -: rhs-          <| scWithPat         -: mbWhere+          <| sc                -: mbWhere       -- FunBind consists of Matches, which we handle below anyway.       TypeSig l names ty ->         c TypeSig