Skip to content

Commit

Permalink
Merge pull request #59 from phischu/v0.5.0
Browse files Browse the repository at this point in the history
All changes for version 0.5.0
  • Loading branch information
phischu committed Nov 26, 2014
2 parents bb210b8 + 63a1aec commit c49aa2d
Show file tree
Hide file tree
Showing 273 changed files with 2,495 additions and 4,204 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Changes
=======

Version 0.5.0
-------------

* Unify type-level and value-level symbols
* Remove fixities from symbol type
* Properly annotate classes and instances
* Inline original name into symbol type
* Remove original package from symbol type
* Annotate symbol references with the way they are referenced

Version 0.4.1
-------------

Expand Down
122 changes: 56 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,22 @@ etc.) exported by every module. For example, here are a couple of entries from
``` json
[
{
"fixity": null,
"origin": {
"name": "map",
"module": "GHC.Base",
"package": "base-4.7.0.0"
},
"entity": "value"
"name": "map",
"entity": "value",
"module": "GHC.Base"
},
{
"fixity": null,
"origin": {
"name": "IO",
"module": "GHC.Types",
"package": "ghc-prim-0.3.1.0"
},
"entity": "data"
"name": "IO",
"entity": "newtype",
"module": "GHC.Types"
},
...
]
```

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.
As you see, each entity is annotated with the module where it was
originally defined. Additionally, class methods, field selectors, and data
constructors are annotated with the class or type they belong to.

### Generating interfaces

Expand All @@ -82,9 +73,10 @@ haskell-names comes with the global package database populated with some core
packages:

% hs-gen-iface pkg list --global
array-0.4.0.2
base-4.7.0.0
ghc-prim-0.3.1.0
integer-simple-0.1.1.0
ghc-prim-0.3.1.0

#### Compiling core packages by hand

Expand Down Expand Up @@ -122,14 +114,9 @@ the package database `NamesDB` defined in `Language.Haskell.Modules.Interfaces`.
Name resolution
---------------

There are two approaches to name resolution.
The `annotateModule` function annotates the module with scoping information.

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

Expand All @@ -139,7 +126,10 @@ Let's say you have a module and you want to find out whether it uses
`Prelude.head`.

``` haskell
module Main where

import Language.Haskell.Exts.Annotated
import qualified Language.Haskell.Exts as UnAnn (Name(Ident))
import Language.Haskell.Names
import Language.Haskell.Names.Interfaces
import Distribution.HaskellSuite
Expand All @@ -148,12 +138,12 @@ 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 :: IO ()
main = do

-- read the program's source from stdin
Expand All @@ -178,44 +168,46 @@ main = do
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
]
-- | The `findHeads` function finds all occurrences of the `head` symbol in
-- a given AST of a Haskell module. It needs access to stored name information
-- and therefore runs in `ModuleT`.
findHeads :: Module SrcSpanInfo -> ModuleT [Symbol] IO [SrcSpanInfo]
findHeads ast = do

-- First we get all symbols exported from `Prelude` with `getModuleInfo`.
symbols <- fromMaybe (error "Prelude not found") <$>
getModuleInfo "Prelude"

-- Then we filter those for the one with name `"head"`.
let
headSymbol =
fromMaybe (error "Prelude.head not found") (listToMaybe (do
symbol <- symbols
guard (symbolName symbol == UnAnn.Ident "head")
return symbol))

-- We annotate the given ast.
annotatedAst <-
annotateModule
Haskell2010 -- base language
[] -- set of extensions
ast

-- We get a list of all annotations from the annotated module.
let
annotations = Foldable.toList annotatedAst

-- A `GlobalSymbol` annotation means that the annotated name refers to a
-- global symbol. It also contains the qualified name that corresponds
-- to how it is referenced but that is not needed here.
headUsages = nub (do
Scoped (GlobalSymbol globalSymbol _) location <- annotations
guard (globalSymbol == headSymbol)
return location)

-- And finally we return all found usages.
return headUsages

return headUsages
```

#### Example invocation
Expand Down Expand Up @@ -263,20 +255,18 @@ See the [list of all issues][issues].
* 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

Maintainers
-----------

[Roman Cheplyaka](https://github.com/feuerbach) is the primary maintainer.
[Philipp Schuster](https://github.com/phischu) is the primary maintainer.

[Adam Bergmark](https://github.com/bergmark) is the backup maintainer. Please
get in touch with him if the primary maintainer cannot be reached.
77 changes: 77 additions & 0 deletions examples/HeadUsages.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module Main where

import Language.Haskell.Exts.Annotated
import qualified Language.Haskell.Exts as UnAnn (Name(Ident))
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.Foldable as Foldable
import Text.Printf
import Control.Applicative
import Control.Monad

main :: IO ()
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 [Symbol] IO [SrcSpanInfo]
findHeads ast = do
-- first of all, figure out the canonical name of "Prelude.head"
-- (hint: it's "GHC.List.head")
symbols <- fromMaybe (error "Prelude not found") <$> getModuleInfo "Prelude"
let
-- we walk through all values defined in Prelude and look for
-- one with name "head"
headSymbol =
fromMaybe (error "Prelude.head not found") (listToMaybe (do
symbol <- symbols
guard (symbolName symbol == UnAnn.Ident "head")
return symbol))

-- 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 headSymbol
headUsages = nub (do
Scoped (GlobalSymbol globalSymbol _) location <- annotations
guard (globalSymbol == headSymbol)
return location)

return headUsages
6 changes: 3 additions & 3 deletions haskell-names.cabal
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Name: haskell-names
Version: 0.4.1
Version: 0.5.0
License: BSD3
Author: Roman Cheplyaka, Lennart Augustsson
Maintainer: Roman Cheplyaka <roma@ro-che.info>
Author: Philipp Schuster, Roman Cheplyaka, Lennart Augustsson
Maintainer: Philipp Schuster
Category: Language
Synopsis: Name resolution library for Haskell
Description:
Expand Down
2 changes: 1 addition & 1 deletion hs-gen-iface/hs-gen-iface.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Name: hs-gen-iface
Version: 0.2
Version: 0.5.0
License: MIT
License-file: LICENSE
Author: Roman Cheplyaka
Expand Down
2 changes: 1 addition & 1 deletion hs-gen-iface/src/hs-gen-iface.hs
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@ compile buildDir mbLang exts cppOpts pkgName pkgdbs deps files = do

createDirectoryIfMissingVerbose silent True (dropFileName ifaceFile)

writeInterface ifaceFile $ qualifySymbols pkgName syms
writeInterface ifaceFile syms
2 changes: 1 addition & 1 deletion libraries/array-0.4.0.2/Data/Array.names
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"origin":{"name":"!","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"//","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"accum","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"accumArray","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"array","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"assocs","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"bounds","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"elems","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"indices","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"ixmap","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"listArray","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"value"},{"origin":{"name":"inRange","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"method","class":{"name":"Ix","module":"GHC.Arr","package":"base-4.7.0.0"}},{"origin":{"name":"index","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"method","class":{"name":"Ix","module":"GHC.Arr","package":"base-4.7.0.0"}},{"origin":{"name":"range","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"method","class":{"name":"Ix","module":"GHC.Arr","package":"base-4.7.0.0"}},{"origin":{"name":"rangeSize","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"method","class":{"name":"Ix","module":"GHC.Arr","package":"base-4.7.0.0"}},{"origin":{"name":"Array","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"data"},{"origin":{"name":"Ix","module":"GHC.Arr","package":"base-4.7.0.0"},"fixity":null,"entity":"class"}]
[{"name":"inRange","class":"Ix","entity":"method","module":"GHC.Arr"},{"name":"index","class":"Ix","entity":"method","module":"GHC.Arr"},{"name":"range","class":"Ix","entity":"method","module":"GHC.Arr"},{"name":"rangeSize","class":"Ix","entity":"method","module":"GHC.Arr"},{"name":"Ix","entity":"class","module":"GHC.Arr"},{"name":"Array","entity":"data","module":"GHC.Arr"},{"name":"array","entity":"value","module":"GHC.Arr"},{"name":"listArray","entity":"value","module":"GHC.Arr"},{"name":"accumArray","entity":"value","module":"GHC.Arr"},{"name":"!","entity":"value","module":"GHC.Arr"},{"name":"bounds","entity":"value","module":"GHC.Arr"},{"name":"indices","entity":"value","module":"GHC.Arr"},{"name":"elems","entity":"value","module":"GHC.Arr"},{"name":"assocs","entity":"value","module":"GHC.Arr"},{"name":"//","entity":"value","module":"GHC.Arr"},{"name":"accum","entity":"value","module":"GHC.Arr"},{"name":"ixmap","entity":"value","module":"GHC.Arr"}]
Loading

0 comments on commit c49aa2d

Please sign in to comment.