Copyright | (c) Alec Theriault 2017-2018 |
---|---|
License | BSD-style |
Maintainer | alec.theriault@gmail.com |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
This module provides functions for turning ASTs into values of type Doc
. These values can then be
rendered into concrete string types using functions from the prettyprinter
package. This has some
advantages over printing plain old strings:
- Backend independent: you can use a variety of existing backends to efficiently render to all
sorts of formats like
Text
,String
, HTML, and terminal. Dynamic layouts: the AST will render differently depending on the desired page width
>>>
:set -XTypeApplications -XOverloadedStrings
>>>
import Language.Rust.Parser
>>>
import Data.Text.Prettyprint.Doc.Util ( putDocW )
>>>
let src = parse' @(SourceFile Span) "fn foo(x: i32, y: i32, z: i32) -> i32 { x - y + z }"
>>>
let doc = pretty' src <> "\n"
>>>
putDocW 80 doc
fn foo(x: i32, y: i32, z: i32) -> i32 { x - y + z }>>>
putDocW 10 doc
fn foo( x: i32, y: i32, z: i32, ) -> i32 { x - y + z }- Annotations: Depending on the backend you are using to render the
Doc
, annotations can determine colours, styling, links, etc.
The examples below assume the following GHCi flag and import:
>>>
:set -XOverloadedStrings
>>>
import Language.Rust.Syntax.AST
- pretty :: (Resolve a, Pretty a) => a -> Either ResolveFail (Doc b)
- pretty' :: (Resolve a, Pretty a) => a -> Doc b
- prettyAnnotated :: (Resolve (f a), PrettyAnnotated f) => f a -> Either ResolveFail (Doc a)
- prettyAnnotated' :: (Resolve (f a), PrettyAnnotated f) => f a -> Doc a
- writeSourceFile :: (Monoid a, Typeable a) => Handle -> SourceFile a -> IO ()
- writeTokens :: Handle -> [Spanned Token] -> IO ()
- class Pretty a where
- class PrettyAnnotated p where
- data Doc ann :: * -> *
- class Resolve a where
- data ResolveFail = ResolveFail [Dynamic] String
- data Issue = Issue {}
- data Severity
- = Clean
- | Warning
- | Correction
- | Error
Printing
pretty :: (Resolve a, Pretty a) => a -> Either ResolveFail (Doc b) Source #
Resolve (see the Resolve
typeclass) and pretty print something.
>>>
let one = Lit [] (Int Dec 1 Unsuffixed ()) ()
>>>
let two = Lit [] (Int Dec 2 Unsuffixed ()) ()
>>>
let three = Lit [] (Int Dec 3 Unsuffixed ()) ()
>>>
let bogusVar = PathExpr [] Nothing (Path False [PathSegment "let" Nothing ()] ()) ()
>>>
pretty (Binary [] MulOp (Binary [] AddOp one two ()) three ())
Right (1 + 2) * 3>>>
pretty (Binary [] AddOp one bogusVar ())
Left (invalid AST (identifier `let' is a keyword))
pretty' :: (Resolve a, Pretty a) => a -> Doc b Source #
Same as pretty
, but throws a ResolveFail
exception on invalid ASTs. This function is
intended for situations in which you are already stuck catching exceptions - otherwise you should
prefer pretty
.
>>>
let one = Lit [] (Int Dec 1 Unsuffixed ()) ()
>>>
let two = Lit [] (Int Dec 2 Unsuffixed ()) ()
>>>
let three = Lit [] (Int Dec 3 Unsuffixed ()) ()
>>>
let bogusVar = PathExpr [] Nothing (Path False [PathSegment "let" Nothing ()] ()) ()
>>>
pretty' (Binary [] MulOp (Binary [] AddOp one two ()) three ())
(1 + 2) * 3>>>
pretty' (Binary [] AddOp one bogusVar ())
*** Exception: invalid AST (identifier `let' is a keyword))
prettyAnnotated :: (Resolve (f a), PrettyAnnotated f) => f a -> Either ResolveFail (Doc a) Source #
Resolve (see the Resolve
typeclass) and pretty print something with annotations. Read more
about annotations in Data.Text.Prettyprint.Doc.
fmap Data.Text.Prettyprint.Doc.noAnnotate . prettyAnnotated = pretty
prettyAnnotated' :: (Resolve (f a), PrettyAnnotated f) => f a -> Doc a Source #
Same as prettyAnnotated
, but throws a ResolveFail
exception on invalid ASTs. This function
is intended for situations in which you are already stuck catching exceptions - otherwise you
should prefer prettyAnnotated
.
Data.Text.Prettyprint.Doc.noAnnotate . prettyAnnotated' = pretty'
writeSourceFile :: (Monoid a, Typeable a) => Handle -> SourceFile a -> IO () Source #
Given a handle to a file, write a SourceFile
in with a desired width of 100 characters.
writeTokens :: Handle -> [Spanned Token] -> IO () Source #
Given a handle to a file, write a SourceFile
in with a desired width of 100 characters.
The Span
associated with the tokens (if present) will be used as a hint to for spacing
out the tokens.
Describes things that can be pretty printed
prettyUnresolved :: a -> Doc b Source #
Pretty print the given value without resolving it.
class PrettyAnnotated p where Source #
Similar to Pretty
, but for types which are parametrized over an annotation type.
prettyAnnUnresolved :: p a -> Doc a Source #
Pretty print the given value without resolving it, adding annotations in the Doc
whenever
possible.
Resolving
class Resolve a where Source #
Since it is possible to have well-typed Haskell expressions which represent invalid Rust ASTs,
it is convenient to fix, warn, or fail ASTs before printing them. The Resolve
typeclass
provides such a facility.
A non-exhaustive list of the more obvious issues it covers:
- missing parens
- invalid identifiers
- invalid paths (for example, generic arguments on a module path)
- inner attributes on things that support only outer attributes (and vice-versa)
resolveM
resolve :: a -> Either ResolveFail a Source #
Convert some value to its resolved form. Informally, resolving a value involves checking that its invariants hold and, if they don't, report an error message or adjust the value so that the invariant holds.
A value of a type satsifying Parse
and Pretty
is resolved if
is an identity
operation on it. We further expect that parse
. pretty
resolve
be an identity operation on any output of
parse
.
Same as resolve
, but throws a ResolveFail
exception if it cannot resolve. Although
this function should not be used, it summarizes nicely the laws around Resolve
:
parse' . pretty' . resolve' == id
resolve' . parse' = parse'
resolveVerbose :: a -> (a, Severity, [Issue]) Source #
Error reporting
data ResolveFail Source #
Exceptions that occur during resolving. Unlike parse errors, we don't have positional information. Instead, we try to provide some context via a list of syntax trees which let you "zoom out" from the problematic node.
Show ResolveFail Source # | Does not show context information |
Exception ResolveFail Source # | |
Localized information about an issue in a syntax tree
Issue | |
|
Diagnostic for how severe an Issue
is
Clean | Everything is normal (this variant is returned when there was nothing to resolve) |
Warning | There is something fishy looking (AST is valid, but may not be what you expect) |
Correction | The AST was invalid, but in a way that could be corrected |
Error | The AST was invalid in some way that could not be automatically fixed |