Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
judah committed Jul 9, 2019
0 parents commit 1346ef0
Show file tree
Hide file tree
Showing 33 changed files with 2,391 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.stack-work/
dist/
# Generated automatically by hpack:
*.cabal
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# How to Contribute

We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## Code reviews

All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

## Community Guidelines

This project follows
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Changelog for haskell-syntax

## Unreleased changes
28 changes: 28 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Copyright 2019 Google LLC

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.

* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ghc-source-gen

`ghc-source-gen` is a Haskell library for constructing Haskell syntax trees using the GHC API. This package is compatible with multiple versions of GHC: currently,= 8.2, 8.4, 8.6, and 8.8.

This is not an officially supported Google product.

## Example

This example constructs and prints a module defining the
`const` function:

```haskell
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
import GHC.SourceGen
import GHC.Paths (libdir)

constModule :: HsModule'
constModule =
module' (Just "Const") (Just [var "const"]) []
[ typeSig "const" $ a --> b --> a
, funBind "const" $ matchRhs [wildP, x] x
]
where
a = var "a"
b = var "b"
x = var "x"

main = runGhc (Just libdir) $ putPpr constModule
```

Which will output:

```
module Const (
const
) where
const :: a -> b -> a
const _ x = x
```

## Syntax Types

GHC represents Haskell syntax trees with several parametrized datatypes; for example: `HsExpr p` for expressions, `HsDecl p` for declarations, etc. The parameter `p` determines which stage of compilation that data has last completed: parsing, renaming, or type-checking.

`ghc-source-gen` constructs values as GHC would represent them
immediately after the parsing step. In ghc-8.6, that
corresponds to `p` being `GhcPs`. It defines several type
synonyms, such as:

```haskell
type HsExpr' = HsExpr GhcPs
type HsType' = HsType GhcPs
type HsDecl' = HsDecl GhcPs
type HsModule' = HsModule GhcPs
-- etc.
```

GHC's datatypes generally contain location information in the
form of [`SrcSpan`](http://hackage.haskell.org/package/ghc/docs/SrcLoc.html#t:SrcSpan) values which point to their original
location in a source file. `ghc-source-gen` constructs values
at runtime, so it uses a dummy value for `SrcSpan` on using a
dummy SrcSpan. (GHC does something similar for code written at the interactive GHCi prompt.)

`ghc-source-gen` aims to be a low-level wrapper around GHC's
types. In particular, it does not explicitly help the user
generate unique names like, for example, `template-haskell`'s
[`newName`](http://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#v:newName)
action. However, we may add support for that in future
versions of this library.
8 changes: 8 additions & 0 deletions Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Copyright 2019 Google LLC
--
-- Use of this source code is governed by a BSD-style
-- license that can be found in the LICENSE file or at
-- https://developers.google.com/open-source/licenses/bsd

import Distribution.Simple
main = defaultMain
17 changes: 17 additions & 0 deletions check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
# Copyright 2019 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

# This script tests that ghc-source-gen works on multiple GHC versions.
# TODO: turn this into a CI script.

set -ueo pipefail

for flag in --resolver={lts-11.22,lts-12.8,lts-13.23} --stack-yaml=stack-8.8.yaml
do
echo ====== $flag ======
stack test $flag ghc-source-gen
done
98 changes: 98 additions & 0 deletions ghc-show-ast/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
-- Copyright 2019 Google LLC
--
-- Use of this source code is governed by a BSD-style
-- license that can be found in the LICENSE file or at
-- https://developers.google.com/open-source/licenses/bsd

{-# LANGUAGE GADTs #-}
module Main where

import Data.Data
import Data.Typeable (cast)
import Language.Haskell.GHC.ExactPrint.Parsers
import System.Environment (getArgs)
import Text.PrettyPrint

import FastString
import Name
( Name
, isExternalName
, isInternalName
, isSystemName
, isWiredInName
, nameOccName
, nameUnique
)
import OccName
( OccName
, occNameSpace
, occNameString
, NameSpace
, varName
, dataName
, tvName
, tcClsName
)

main :: IO ()
main = do
[f] <- getArgs
result <- parseModule f
case result of
Left err -> print err
Right (_, ps) -> do
print $ gPrint ps

gPrint :: Data a => a -> Doc
gPrint x
| showConstr c == "L", [_,e] <- xs = e
| showConstr c == "(:)" = gPrintList x
| Just occ <- cast x = text $ showOccName occ
| Just name <- cast x = text $ showName name
| Just s <- cast x = text $ showFastString s
| otherwise =
hang (text $ showConstr c) 2 (sep $ map parens xs)
where
c = toConstr x
xs = gmapQ gPrint x

gPrintList :: Data a => a -> Doc
gPrintList = brackets . sep . punctuate comma . elems
where
elems :: Data b => b -> [Doc]
elems xs = case gmapQ SomeData xs of
[] -> []
[x,y] -> renderCons x y
_ -> error $ "gPrintList: unexpected number of fields"
renderCons :: SomeData -> SomeData -> [Doc]
renderCons (SomeData x) (SomeData y) = gPrint x : elems y

data SomeData where
SomeData :: Data a => a -> SomeData

showOccName :: OccName -> String
showOccName o = "OccName{" ++ showNameSpace (occNameSpace o)
++ "," ++ show (occNameString o) ++ "}"

showFastString :: FastString -> String
showFastString = show . unpackFS

showNameSpace :: NameSpace -> String
showNameSpace ns
| ns == varName = "VarName"
| ns == dataName = "DataName"
| ns == tvName = "TvName"
| ns == tcClsName = "TcClsName"
| otherwise = "Unknown"

showName :: Name -> String
showName n = "Name{" ++ nameSort ++ ":" ++ showOccName (nameOccName n)
++ "," ++ show (nameUnique n)
++ "}"
where
nameSort
| isExternalName n = "external"
| isInternalName n = "internal"
| isSystemName n = "system"
| isWiredInName n = "wired-in"
| otherwise = "unknown" -- Shouldn't happen; these guards are exhaustive
6 changes: 6 additions & 0 deletions ghc-show-ast/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ghc-show-ast helps debug the behavior of GHC that ghc-source-gen is trying to imitate.
This program parses a source file with GHC and then pretty-prints the AST.

To use:

stack run ghc-show-ast -- path/to/file.hs
16 changes: 16 additions & 0 deletions ghc-show-ast/package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2019 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

name: ghc-show-ast

executables:
ghc-show-ast:
main: Main.hs
dependencies:
- base
- ghc
- ghc-exactprint
- pretty
58 changes: 58 additions & 0 deletions package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2019 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

name: ghc-source-gen
version: 0.1.0.0
github: "google/ghc-source-gen"
license: BSD3
author: "Judah Jacobson"
maintainer: "[email protected]"
copyright: "Google LLC"

extra-source-files:
- README.md
- ChangeLog.md

synopsis: Constructs Haskell syntax trees for the GHC API.
category: Development
description: Please see the README on GitHub at <https://github.com/google/ghc-source-gen>

dependencies:
- base >= 4.7 && < 5
- ghc >= 8.2 && < 8.9

default-extensions:
- DataKinds
- FlexibleInstances
- TypeSynonymInstances

library:
source-dirs: src
other-modules:
- GHC.SourceGen.Binds.Internal
- GHC.SourceGen.Expr.Internal
- GHC.SourceGen.Lit.Internal
- GHC.SourceGen.Name.Internal
- GHC.SourceGen.Syntax.Internal
- GHC.SourceGen.Type.Internal

tests:
pprint_examples:
main: pprint_examples.hs
source-dirs: tests
dependencies:
- ghc-source-gen
- ghc-paths == 0.1.*

# TODO: Fill out this test, and use it to replace pprint_examples.
pprint_test:
main: pprint_test.hs
source-dirs: tests
dependencies:
- ghc-source-gen
- ghc-paths == 0.1.*
- tasty
- tasty-hunit
45 changes: 45 additions & 0 deletions src/GHC/SourceGen.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
-- Copyright 2019 Google LLC
--
-- Use of this source code is governed by a BSD-style
-- license that can be found in the LICENSE file or at
-- https://developers.google.com/open-source/licenses/bsd

-- | This module exports all of the definitions in this package in one
-- convenient location.
--
-- For more details and examples of usage, see
-- <https://github.com/google/ghc-source-gen>.
module GHC.SourceGen
( -- * Syntax types
-- | These modules declare combinators for constructing different parts
-- of a GHC syntax tree.
module GHC.SourceGen.Syntax,
module GHC.SourceGen.Name,
module GHC.SourceGen.Decl,
module GHC.SourceGen.Expr,
module GHC.SourceGen.Module,
module GHC.SourceGen.Pat,
module GHC.SourceGen.Type,
-- * Overloaded combinators
-- | Certain concepts make sense in different
-- parts of Haskell syntax. For example, 'var' may be used in
-- expressions, types, patterns, and import or export lists.
module GHC.SourceGen.Binds,
module GHC.SourceGen.Lit,
module GHC.SourceGen.Overloaded,
-- * Renders Haskell syntax into text
module GHC.SourceGen.Pretty,
) where

import GHC.SourceGen.Binds
import GHC.SourceGen.Decl
import GHC.SourceGen.Expr
import GHC.SourceGen.Lit
import GHC.SourceGen.Module
import GHC.SourceGen.Name
import GHC.SourceGen.Overloaded
import GHC.SourceGen.Pat
import GHC.SourceGen.Pretty
import GHC.SourceGen.Syntax
import GHC.SourceGen.Type

Loading

0 comments on commit 1346ef0

Please sign in to comment.