diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+# 0.1.0.0
+
+* Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author Kwang Yul Seo (c) 2016
+
+All rights reserved.
+
+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 Author name here nor the names of other
+      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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# language-dart
+
+[![Build Status](https://travis-ci.org/kseo/language-dart.svg?branch=master)](https://travis-ci.org/kseo/language-dart)
+
+A library for manipulating Dart source: abstract syntax and pretty-printer
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/language-dart.cabal b/language-dart.cabal
new file mode 100644
--- /dev/null
+++ b/language-dart.cabal
@@ -0,0 +1,38 @@
+name:                language-dart
+version:             0.1.0.0
+synopsis:            Manipulating Dart source: abstract syntax and pretty-printer
+description:         Please see README.md
+homepage:            https://github.com/kseo/language-dart#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Kwang Yul Seo
+maintainer:          kwangyul.seo@gmail.com
+copyright:           Kwang Yul Seo 2016
+category:            Language
+stability:           Experimental
+build-type:          Simple
+extra-source-files:  README.md
+                     CHANGELOG.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Language.Dart.Pretty
+                       Language.Dart.Syntax
+  build-depends:       base >= 4.7 && < 5
+                     , pretty >= 1.1
+  default-language:    Haskell2010
+
+test-suite language-dart-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , hspec
+                     , language-dart
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/kseo/language-dart
diff --git a/src/Language/Dart/Pretty.hs b/src/Language/Dart/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Dart/Pretty.hs
@@ -0,0 +1,754 @@
+module Language.Dart.Pretty
+  ( Pretty
+  , prettyPrint
+  ) where
+
+import Data.Char (toLower)
+import Data.List (partition)
+import Text.PrettyPrint
+import Text.Printf (printf)
+
+import Language.Dart.Syntax
+
+-- FIXME: Don't omit comments
+
+prettyPrint :: Pretty a => a -> String
+prettyPrint = show . pretty
+
+parenPrec :: Int -> Int -> Doc -> Doc
+parenPrec inheritedPrec currentPrec t
+  | inheritedPrec > currentPrec = parens t
+  | otherwise                   = t
+
+class Pretty a where
+  pretty :: a -> Doc
+  pretty = prettyPrec 0
+
+  prettyPrec :: Int -> a -> Doc
+  prettyPrec _ = pretty
+
+instance Pretty MapLiteralEntry where
+  prettyPrec p (MapLiteralEntry key value) =
+    hsep [ prettyPrec p key
+         , colon
+         , prettyPrec p value
+         ]
+
+instance Pretty TypedLiteral where
+  prettyPrec p (MapLiteral isConst mTypeArguments entries)  =
+    hsep [ optKeyword isConst "const"
+         , maybePP p mTypeArguments
+         ] <> braces (hsep (ppIntersperse p comma entries))
+
+  prettyPrec p (ListLiteral isConst mTypeArguments elements) =
+    hsep [ optKeyword isConst "const"
+         , maybePP p mTypeArguments
+         ] <> brackets (hsep (ppIntersperse p comma elements))
+
+instance Pretty Literal where
+  prettyPrec p (NullLiteral)      = text "null"
+  prettyPrec p (BooleanLiteral b) = text . map toLower $ show b
+  prettyPrec p (DoubleLiteral d)  = text (show d)
+  prettyPrec p (IntegerLiteral i) = text (show i)
+  prettyPrec p (TypedLiteral t)   = prettyPrec p t
+  prettyPrec p (StringLiteral' s) = prettyPrec p s
+  prettyPrec p (SymbolLiteral ts) = pound <> hsep (punctuate period (map text ts))
+
+instance Pretty InterpolationElement where
+  prettyPrec p (InterpolationString s) = text s
+
+  prettyPrec p (InterpolationExpression expression) =
+    dollar <> braces (prettyPrec p expression)
+
+instance Pretty SingleStringLiteral where
+  prettyPrec p (SimpleStringLiteral value) =
+    doubleQuotes (text (concatMap escapeString value))
+
+  prettyPrec p (StringInterpolation elements) =
+    doubleQuotes (hcat (map (prettyPrec p) elements))
+
+instance Pretty StringLiteral where
+  prettyPrec p (SingleStringLiteral' l) = prettyPrec p l
+
+  prettyPrec p (AdjacentStrings strings) =
+    hsep (map (prettyPrec p) strings)
+
+instance Pretty Combinator where
+  prettyPrec p (ShowCombinator shownNames)  = text "show" <+>
+    hsep (ppIntersperse p comma shownNames)
+
+  prettyPrec p (HideCombinator hiddenNames) = text "hide" <+>
+    hsep (ppIntersperse p comma hiddenNames)
+
+-- FIXME: Handle configurations
+instance Pretty NamespaceDirective where
+  prettyPrec p (ExportDirective _ metadata libraryUri _ combinators) =
+    ppMetadata p metadata $$
+      hsep [ text "export"
+           , prettyPrec p libraryUri
+           , hsep (ppIntersperse p comma combinators)
+           ] <> semi
+
+  prettyPrec p (ImportDirective _ metadata libraryUri _ isDeferred mPrefix combinators) =
+    ppMetadata p metadata $$
+      hsep [ text "import"
+           , prettyPrec  p libraryUri
+           , optKeyword isDeferred "deferred"
+           , maybe empty ((text "as" <+>) . prettyPrec p) mPrefix
+           , hsep (ppIntersperse p comma combinators)
+           ] <> semi
+
+instance Pretty UriBasedDirective where
+  prettyPrec p (NamespaceDirective nsDir) = prettyPrec p nsDir
+
+  prettyPrec p (PartDirective _ metadata partUri) =
+    ppMetadata p metadata $$ prettyPrec p partUri <> semi
+
+instance Pretty Directive where
+  prettyPrec p (UriBasedDirective dir) = prettyPrec p dir
+
+  prettyPrec p (PartOfDirective _ metadata libraryName) =
+    ppMetadata p metadata $$
+      text "part of" <> prettyPrec p libraryName <> semi
+
+  prettyPrec p (LibraryDirective _ metadata libraryName) =
+    ppMetadata p metadata $$
+      text "library" <> prettyPrec p libraryName <> semi
+
+instance Pretty AsyncModifier where
+  prettyPrec p AsyncStar  = text "async*"
+  prettyPrec p Async      = text "async"
+  prettyPrec p SyncStar   = text "sync*"
+  prettyPrec p Sync       = empty
+
+instance Pretty NormalFormalParameter where
+  prettyPrec p (FunctionTypedFormalParameter _ metadata mReturnType identifier mTypeParameters parameters) =
+    ppMetadata p metadata $$
+      hsep [ maybePP p mReturnType
+           , hcat [ prettyPrec p identifier
+                  , maybePP p mTypeParameters
+                  , prettyPrec p parameters
+                  ]
+           ]
+
+  prettyPrec p (FieldFormalParameter _ metadata kind explicitThis identifier) =
+    ppMetadata p metadata $$
+      hsep [ maybePP p kind
+           , opt explicitThis (text "this.") <> prettyPrec p identifier
+           ]
+
+  prettyPrec p (SimpleFormalParameter _ metadata kind identifier) =
+    ppMetadata p metadata $$
+      hsep [ prettyPrec p kind
+           , prettyPrec p identifier
+           ]
+
+instance Pretty FormalParameter where
+  prettyPrec p (NormalFormalParameter' parameter) = prettyPrec p parameter
+
+  prettyPrec p (DefaultFormalParameter parameter kind mDefaultValue) =
+    hsep [ prettyPrec p parameter
+         , maybe empty ((separator kind <+>) . prettyPrec p) mDefaultValue
+         ]
+    where separator Positional = equals
+          separator Named = colon
+
+instance Pretty FormalParameterList where
+  prettyPrec p (FormalParameterList parameters) =
+    let (normals, defaults) = partition isNormal parameters
+     in parens $ hcat [ hsep (ppIntersperse p comma normals)
+                      , opt (not $ null defaults) (comma <+> (matchingBracket (head defaults)) (hsep (ppIntersperse p comma defaults)))
+                      ]
+    where isNormal (NormalFormalParameter' _) = True
+          isNormal _ = False
+          matchingBracket (DefaultFormalParameter _ Positional _) = brackets
+          matchingBracket _ = braces
+
+instance Pretty ConstructorName where
+  prettyPrec p (ConstructorName type' mName) =
+    hsep [ prettyPrec p type'
+         , maybe empty ((period <>) . prettyPrec p) mName
+         ]
+
+instance Pretty SimpleIdentifier where
+  prettyPrec _ (SimpleIdentifier token) = text token
+
+instance Pretty LibraryIdentifier where
+  prettyPrec p (LibraryIdentifier components) =
+    hcat (ppIntersperse p period components)
+
+instance Pretty Identifier where
+  prettyPrec p (SimpleIdentifier' simpleId) = prettyPrec p simpleId
+
+  prettyPrec p (PrefixedIdentifier prefix identifier) =
+    hcat [ prettyPrec p prefix
+         , period
+         , prettyPrec p identifier
+         ]
+
+  prettyPrec p (LibraryIdentifier' libraryName) = prettyPrec p libraryName
+
+instance Pretty TypeArgumentList where
+  prettyPrec p (TypeArgumentList args) =
+    angleBrackets (hsep (ppIntersperse p comma args))
+
+instance Pretty TypeName where
+  prettyPrec p (TypeName name typeArgList) = prettyPrec p name <> maybePP p typeArgList
+
+instance Pretty PropertyKeyword where
+  prettyPrec p Get   = text "get"
+  prettyPrec p Set   = text "set"
+  prettyPrec p Empty = empty
+
+instance Pretty ArgumentList where
+  prettyPrec p (ArgumentList args) =
+    parens (hsep (ppIntersperse p comma args))
+
+instance Pretty Annotation where
+  prettyPrec p (Annotation name mConstructorName mArguments) =
+    hcat [ at
+         , prettyPrec p name
+         , maybe empty ((period <>) . prettyPrec p) mConstructorName
+         , maybePP p mArguments
+         ]
+
+instance Pretty ExtendsClause where
+  prettyPrec p (ExtendsClause superclass) = text "extends" <+>
+    prettyPrec p superclass
+
+instance Pretty WithClause where
+  prettyPrec p (WithClause mixinTypes) = text "with" <+>
+    hsep (ppIntersperse p comma mixinTypes)
+
+instance Pretty ImplementsClause where
+  prettyPrec p (ImplementsClause interfaces) = text "implements" <+>
+    hsep (ppIntersperse p comma interfaces)
+
+instance Pretty TypeAlias where
+  prettyPrec p (ClassTypeAlias _ metadata name mTypeParameters isAbstract superclass withClause mImplementsClause) =
+    ppMetadata p metadata $$
+      hsep [ optKeyword isAbstract "abstract"
+           , text "class"
+           , hcat [ prettyPrec p name
+                  , maybePP p mTypeParameters
+                  ]
+           , equals
+           , prettyPrec p superclass
+           , prettyPrec p withClause
+           , maybePP p mImplementsClause
+           ] <> semi
+
+  prettyPrec p (FunctionTypeAlias _ metadata mReturnType name mTypeParameters parameters) =
+    ppMetadata p metadata $$
+      hsep [ text "typedef"
+           , maybePP p mReturnType
+           , hcat [ prettyPrec p name
+                  , maybePP p mTypeParameters
+                  , prettyPrec p parameters
+                  ]
+           ] <> semi
+
+instance Pretty EnumConstantDeclaration where
+  prettyPrec p (EnumConstantDeclaration _ metadata name) =
+    ppMetadata p metadata $$ prettyPrec p name
+
+instance Pretty TypeParameter where
+  prettyPrec p (TypeParameter _ metadata name mBound) =
+    ppMetadata p metadata $$
+      hsep [ prettyPrec p name
+           , maybe empty ((text "extends" <+>) . prettyPrec p) mBound
+           ]
+
+instance Pretty TypeParameterList where
+  prettyPrec p (TypeParameterList typeParameters) =
+    angleBrackets (hsep (ppIntersperse p comma typeParameters))
+
+instance Pretty Label where
+  prettyPrec p (Label label) = prettyPrec p label <> char ':'
+
+instance Pretty FinalConstVarOrType where
+  prettyPrec p (FCVTFinal type')  = text "final" <+> prettyPrec p type'
+  prettyPrec p (FCVTConst type')  = text "const" <+> prettyPrec p type'
+  prettyPrec p (FCVTType type')   = prettyPrec p type'
+  prettyPrec p FCVTVar            = text "var"
+
+instance Pretty FinalVarOrType where
+  prettyPrec p (FVTFinal type') = text "final" <+> prettyPrec p type'
+  prettyPrec p (FVTType type')  = prettyPrec p type'
+  prettyPrec p FVTVar           = text "var"
+
+instance Pretty VariableDeclaration where
+  prettyPrec p (VariableDeclaration name mInitializer) =
+    hsep [ prettyPrec p name
+         , maybe empty ((equals <+>) . prettyPrec p) mInitializer
+         ]
+
+instance Pretty VariableDeclarationList where
+  prettyPrec p (VariableDeclarationList _ metadata kind variables) =
+    ppMetadata p metadata $$
+      prettyPrec p kind <+> hsep (ppIntersperse p comma variables)
+
+instance Pretty CatchClause where
+  prettyPrec p (CatchClause mExceptionType exceptionParameter mStackTraceParameter body) =
+    case mExceptionType of
+      Nothing -> text "catch" <+> parens (ppExceptionParameter p exceptionParameter mStackTraceParameter) $$ prettyPrec p body
+      Just exceptionType -> text "on" <+> prettyPrec p exceptionType $$ prettyPrec p body
+    where ppExceptionParameter p ep Nothing = prettyPrec p ep
+          ppExceptionParameter p ep (Just stp) = hsep (ppIntersperse p comma [ep, stp])
+
+instance Pretty SwitchMember where
+  prettyPrec p (SwitchCase labels expression statements) =
+    vcat (map (prettyPrec p) labels) $$
+      vcat (ppSwitchCase p expression : map (nest 2 . prettyPrec p) statements)
+    where ppSwitchCase p expression = text "case" <+> prettyPrec p expression <> colon
+
+  prettyPrec p (SwitchDefault labels statements) =
+    vcat (map (prettyPrec p) labels) $$
+      vcat (ppSwitchDefault : map (nest 2 . prettyPrec p) statements)
+    where ppSwitchDefault = text "default" <> colon
+
+instance Pretty DeclaredIdentifier where
+  prettyPrec p (DeclaredIdentifier _ metadata kind identifier) =
+    ppMetadata p metadata $$
+      hsep [ prettyPrec p kind
+           , prettyPrec p identifier
+           ]
+
+instance Pretty Statement where
+  prettyPrec p (Block' block) = prettyPrec p block
+
+  prettyPrec p (VariableDeclarationStatement variableList) =
+    prettyPrec p variableList <> semi
+
+  prettyPrec p (ForStatement mVariableList mInitialization mCondition updaters body) =
+    text "for" <+> (parens $ hsep [ maybe empty ((<> semi) . prettyPrec p) mVariableList
+                                  , maybe empty ((<> semi) . prettyPrec p) mInitialization
+                                  , maybePP p mCondition <> semi
+                                  , hsep (ppIntersperse p comma updaters)
+                                  ]) $+$ prettyNestedStmt p body
+
+  prettyPrec p (ForEachStatementWithDeclaration isAwait loopVariable iterator body) = undefined
+    hsep [ optKeyword isAwait "await"
+         , text "for"
+         , parens $ hsep [ prettyPrec p loopVariable
+                         , text "in"
+                         , prettyPrec p iterator
+                         ]
+         , prettyPrec p body
+         ]
+
+  prettyPrec p (ForEachStatementWithReference isAwait identifier iterator body) =
+    hsep [ optKeyword isAwait "await"
+         , text "for"
+         , parens $ hsep [ prettyPrec p identifier
+                         , text "in"
+                         , prettyPrec p iterator
+                         ]
+         , prettyPrec p body
+         ]
+
+  prettyPrec p (WhileStatement condition body) =
+    text "while" <+> parens (prettyPrec p condition) $+$ prettyNestedStmt 0 body
+
+  prettyPrec p (DoStatement body condition) =
+    text "do" $+$ prettyPrec p body <+> text "while" <+> parens (prettyPrec p condition) <> semi
+
+  prettyPrec p (SwitchStatement expression members) =
+    text "switch" <+> parens (prettyPrec p expression)
+      $$ braceBlock (map (prettyPrec p) members)
+
+  prettyPrec p (IfStatement condition thenStatement mElseStatement) =
+    text "if" <+> parens (prettyPrec p condition) $+$
+      prettyNestedStmt 0 thenStatement $+$ ppElseStatement mElseStatement
+    where ppElseStatement Nothing = empty
+          ppElseStatement (Just elseStatement) = text "else" $+$ prettyNestedStmt 0 elseStatement
+
+  prettyPrec p (TryStatement body catchCaluses mFinallyBlock) =
+    text "try" $$ prettyPrec p body $$
+      vcat (map (prettyPrec p) catchCaluses ++ [ppFinally mFinallyBlock])
+    where ppFinally Nothing = empty
+          ppFinally (Just finally) = text "finally" $$ prettyPrec p finally
+
+  prettyPrec p (BreakStatement mLabel) =
+    text "break" <+> maybePP p mLabel <> semi
+
+  prettyPrec p (ContinueStatement mLabel) =
+    text "continue" <+> maybePP p mLabel <> semi
+
+  prettyPrec p (ReturnStatement mExpression) =
+    text "return" <+> maybePP p mExpression <> semi
+
+  prettyPrec p (ExpressionStatement expression) =
+    prettyPrec p expression <> semi
+
+  prettyPrec p (FunctionDeclarationStatement functionDeclaration) =
+    prettyPrec p functionDeclaration <> semi
+
+  -- FIXME: Show message
+  prettyPrec p (AssertStatement condition _) =
+    hcat [ text "assert"
+         , parens (prettyPrec p condition)
+         , semi
+         ]
+
+  prettyPrec p (YieldStatement isStar expression) =
+    hsep [ text "yield"
+         , opt isStar star
+         , prettyPrec p expression
+         ] <> semi
+
+  prettyPrec p (EmptyStatement) = semi
+
+  prettyPrec p (LabeledStatement labels statement) =
+    vcat (map (prettyPrec p) labels) $$
+      prettyPrec p statement
+
+instance Pretty Block where
+  prettyPrec p (Block statements) = braceBlock (map (prettyPrec p) statements)
+
+instance Pretty NewOrConst where
+  prettyPrec p NCNew    = text "new"
+  prettyPrec p NCConst  = text "const"
+
+instance Pretty InvocationExpression where
+  prettyPrec p (FunctionExpressionInvocation function mTypeArguments argumentList) =
+    hcat [ prettyPrec p function
+         , maybePP p mTypeArguments
+         , prettyPrec p argumentList
+         ]
+
+  prettyPrec p (MethodInvocation mTarget methodName mTypeArguments argumentList) =
+    hcat [ maybe empty ((<> period) . prettyPrec p) mTarget
+         , prettyPrec p methodName
+         , maybePP p mTypeArguments
+         , prettyPrec p argumentList
+         ]
+
+instance Pretty Expression where
+  prettyPrec p (Literal' literal) = prettyPrec p literal
+
+  prettyPrec p (Identifier' identifier) = prettyPrec p identifier
+
+  prettyPrec p (PrefixExpression  operator operand) =
+    parenPrec p 15 $ text operator <> prettyPrec 15 operand
+
+  prettyPrec p (PostfixExpression operand operator) =
+    parenPrec p 16 $ prettyPrec 15 operand <> text operator
+
+  prettyPrec p (BinaryExpression leftOperand operator rightOperand) =
+    let prec = opPrec operator
+     in parenPrec p prec $ hsep [ prettyPrec prec leftOperand
+                                , text operator
+                                , prettyPrec prec rightOperand
+                                ]
+
+  prettyPrec p (AssignmentExpression leftHandSide operator rightHandSide) =
+    hsep [ prettyPrec p leftHandSide
+         , text operator
+         , prettyPrec p rightHandSide
+         ]
+
+  prettyPrec p (FunctionExpression' functionExpression) = prettyPrec p functionExpression
+
+  prettyPrec p (InstanceCreationExpression newOrConst constructorName argumentList) =
+    hsep [ prettyPrec p newOrConst
+         , hcat [ prettyPrec p constructorName
+                , prettyPrec p argumentList
+                ]
+         ]
+
+  prettyPrec p (AsExpression expression type') =
+    parenPrec p 8 $ hsep [ prettyPrec 8 expression
+                         , text "as"
+                         , prettyPrec 8 type'
+                         ]
+
+  prettyPrec p (IsExpression expression isNot type') =
+    parenPrec p 8 $ hsep [ prettyPrec 8 expression
+                         , text "is"
+                         , opt isNot exclamation
+                         , prettyPrec 8 type'
+                         ]
+
+  prettyPrec p (ThrowExpression expression) = text "throw" <+> prettyPrec p expression
+  prettyPrec p (RethrowExpression)          = text "rethrow"
+
+  prettyPrec p (ThisExpression)  = text "this"
+  prettyPrec p (SuperExpression) = text "super"
+
+  prettyPrec p (ParenthesizedExpression expression) = parens (prettyPrec p expression)
+
+  prettyPrec p (PropertyAccess target propertyName) =
+    hcat [ prettyPrec p target
+         , period
+         , prettyPrec p propertyName
+         ]
+
+  prettyPrec p (NamedExpression name expression) =
+    hsep [ prettyPrec p name <> colon
+         , prettyPrec p expression
+         ]
+
+  prettyPrec p (InvocationExpression invocationExpression) =
+    prettyPrec p invocationExpression
+
+  prettyPrec p (ConditionalExpression condition thenExpression elseExpression) =
+    parenPrec p 3 $ hsep [ prettyPrec 3 condition
+                         , questionMark
+                         , prettyPrec p thenExpression
+                         , colon
+                         , prettyPrec 3 elseExpression
+                         ]
+
+  prettyPrec p (CascadeExpression target cascadeSections) =
+    let sections = target:cascadeSections
+     in parenPrec p 2 $ hsep (ppIntersperse 2 (text "..") sections)
+
+  prettyPrec p (IndexExpressionForCasecade index) = brackets (prettyPrec p index)
+
+  prettyPrec p (IndexExpressionForTarget target index) =
+    prettyPrec p target <> brackets (prettyPrec p index)
+
+  prettyPrec p (AwaitExpression expression) =
+    hsep [ text "await"
+         , prettyPrec p expression
+         ]
+
+instance Pretty FunctionBody where
+  prettyPrec p (BlockFunctionBody asyncModifier block) =
+    prettyPrec p asyncModifier <+> prettyPrec p block
+
+  prettyPrec p (EmptyFunctionBody) = semi
+
+  prettyPrec p (ExpressionFunctionBody isAsync expression) =
+    hsep [ optKeyword isAsync "async"
+         , text "=>"
+         , prettyPrec p expression
+         ] <> semi
+
+  prettyPrec p (NativeFunctionBody stringLiteral) =
+    text "native" <+> prettyPrec p stringLiteral <> semi
+
+instance Pretty FunctionExpression where
+  prettyPrec p (FunctionExpression mTypeParameters parameters body) =
+    case body of
+      BlockFunctionBody _ _      -> ppParams $$  prettyPrec p body
+      ExpressionFunctionBody _ _ -> ppParams <+> prettyPrec p body
+      _                          -> ppParams <> semi
+    where ppParams = maybePP p mTypeParameters <> prettyPrec p parameters
+
+instance Pretty FunctionDeclaration where
+  prettyPrec p (FunctionDeclaration _ metadata isExternal mReturnType propertyKeyword name (FunctionExpression mTypeParameters parameters body)) =
+    ppMetadata p metadata $$
+      hsep [ optKeyword isExternal "external"
+           , maybePP p mReturnType
+           , prettyPrec p propertyKeyword
+           , hcat [ prettyPrec p name
+                  , maybePP p mTypeParameters
+                  , prettyPrec p parameters
+                  ]
+           ] $$$ prettyPrec p body
+   where ($$$) = case body of
+                   (ExpressionFunctionBody _ _) -> (<+>)
+                   (BlockFunctionBody _ _) -> ($$)
+                   _ -> (<>)
+
+instance Pretty ConstructorInitializer where
+  prettyPrec p (RedirectingConstructorInvocation mConstructorName argumentList) =
+    hcat [ text "this"
+         , maybe empty ((period <>) . prettyPrec p) mConstructorName
+         , prettyPrec p argumentList
+         ]
+
+  prettyPrec p (ConstructorFieldInitializer explicitThis fieldName expression) =
+    hsep [ hcat [ opt explicitThis (text "this.")
+                , prettyPrec p fieldName
+                ]
+         , equals
+         , prettyPrec p expression
+         ]
+
+  prettyPrec p (SuperConstructorInvocation mConstructorName argumentList) =
+    hcat [ text "super"
+         , maybe empty ((period <>) . prettyPrec p) mConstructorName
+         , prettyPrec p argumentList
+         ]
+
+instance Pretty MethodModifier where
+  prettyPrec _ Abstract = text "abstract"
+  prettyPrec _ Static   = text "static"
+
+instance Pretty NamedCompilationUnitMember where
+  prettyPrec p (FunctionDeclaration' funDecl) = prettyPrec p funDecl
+
+  prettyPrec p (TypeAlias typeAlias) = prettyPrec p typeAlias
+
+  prettyPrec p (EnumDeclaration _ metadata name constants) =
+    ppMetadata p metadata $$
+      hsep [ text "enum"
+           , prettyPrec p name
+           ] $$ braceBlock (ppIntersperse p comma constants)
+
+  prettyPrec p (ClassDeclaration _ metadata isAbstract name mTypeParameters mExtendsClause mWithClause mImplementsClause members) =
+    ppMetadata p metadata $$
+      hsep [ optKeyword isAbstract "abstract"
+           , text "class"
+           , prettyPrec p name <> maybePP p mTypeParameters
+           , maybePP p mExtendsClause
+           , maybePP p mWithClause
+           , maybePP p mImplementsClause
+           ] $$ braceBlock (map (prettyPrec p) members)
+
+instance Pretty CompilationUnitMember where
+  prettyPrec p (TopLevelVariableDeclaration _ metadata variableList) =
+    ppMetadata p metadata $$ prettyPrec p variableList
+
+  prettyPrec p (NamedCompilationUnitMember member) = prettyPrec p member
+
+instance Pretty ScriptTag where
+  prettyPrec _ (ScriptTag token) = text token
+
+instance Pretty CompilationUnit where
+  prettyPrec p (CompilationUnit mScriptTag dirs members) =
+    vcat $ [maybePP p mScriptTag] ++ map (prettyPrec p) dirs ++ map (prettyPrec p) members
+
+ppMetadata :: Int -> [Annotation] -> Doc
+ppMetadata p metadata = vcat (map (prettyPrec p) metadata)
+
+instance Pretty ClassMember where
+  prettyPrec p (ConstructorDeclaration _ metadata isExternal isConst isFactory className mName parameters initializers mRedirectedConstructor mBody) =
+    ppMetadata p metadata $$
+      case mRedirectedConstructor of
+        Nothing -> hsep [ optKeyword isExternal "external"
+                        , optKeyword isConst "const"
+                        , optKeyword isFactory "factory"
+                        , hcat [ prettyPrec p className
+                               , maybe empty ((period <>) . prettyPrec p) mName
+                               , prettyPrec p parameters
+                               ]
+                        , opt (not $ null initializers) (colon <+> vcat (ppIntersperse p comma initializers))
+                        ] <> maybe semi (const empty) mBody $$ maybePP p mBody
+        Just redirectedConstructor -> hsep [ optKeyword isConst "const"
+                                           , text "factory"
+                                           , hcat [ prettyPrec p className
+                                                  , maybe empty ((period <>) . prettyPrec p) mName
+                                                  , prettyPrec p parameters
+                                                  ]
+                                           , equals
+                                           , prettyPrec p redirectedConstructor <> semi
+                                           ]
+
+  prettyPrec p (MethodDeclaration _ metadata isExternal methodModifier mReturnType propertyKeyword isOperator name mTypeParameters mParameters body) =
+    ppMetadata p metadata $$
+      hsep [ optKeyword isExternal "external"
+           , maybePP p methodModifier
+           , maybePP p mReturnType
+           , prettyPrec p propertyKeyword
+           , optKeyword isOperator "operator"
+           , hcat [ prettyPrec p name, maybePP p mTypeParameters, maybePP p mParameters]
+           ] $$ prettyPrec p body
+  prettyPrec p (FieldDeclaration _ metadata isStatic fieldList) =
+    ppMetadata p metadata $$
+      optKeyword isStatic "static" <+> prettyPrec p fieldList <> semi
+
+ppIntersperse :: (Pretty a) => Int -> Doc -> [a] -> [Doc]
+ppIntersperse p s as = punctuate s (map (prettyPrec p) as)
+
+-----------------------------------------------------------------------
+---- Help functionality
+prettyNestedStmt :: Int -> Statement -> Doc
+prettyNestedStmt prio b@(Block' _) = prettyPrec prio b
+prettyNestedStmt prio s = nest 2 (prettyPrec prio s)
+
+maybePP :: Pretty a => Int -> Maybe a -> Doc
+maybePP p = maybe empty (prettyPrec p)
+
+pound :: Doc
+pound = char '#'
+
+period :: Doc
+period = char '.'
+
+star :: Doc
+star = char '*'
+
+at :: Doc
+at = char '@'
+
+dollar :: Doc
+dollar = char '$'
+
+questionMark :: Doc
+questionMark = char '?'
+
+exclamation :: Doc
+exclamation = char '!'
+
+angleBrackets :: Doc -> Doc -- ^ Wrap document in @<...>@
+angleBrackets p = char '<' <> p <> char '>'
+
+opt :: Bool -> Doc -> Doc
+opt x a = if x then a else empty
+
+optKeyword :: Bool -> String -> Doc
+optKeyword x s = opt x (text s)
+
+block :: Char -> Char -> [Doc] -> Doc
+block open close xs = char open
+    $+$ nest 2 (vcat xs)
+    $+$ char close
+
+braceBlock :: [Doc] -> Doc
+braceBlock = block '{' '}'
+
+bracketBlock :: [Doc] -> Doc
+bracketBlock = block '[' ']'
+
+escapeGeneral :: Char -> String
+escapeGeneral '\b' = "\\b"
+escapeGeneral '\t' = "\\t"
+escapeGeneral '\n' = "\\n"
+escapeGeneral '\f' = "\\f"
+escapeGeneral '\r' = "\\r"
+escapeGeneral '\\' = "\\\\"
+escapeGeneral c | c >= ' ' && c < '\DEL' = [c]
+                | c <= '\xFFFF' = printf "\\u%04x" (fromEnum c)
+                | otherwise = error $ "Language.Dart.Pretty.escapeGeneral: Char " ++ show c ++ " too large for Dart char"
+
+escapeChar :: Char -> String
+escapeChar '\'' = "\\'"
+escapeChar c = escapeGeneral c
+
+escapeString :: Char -> String
+escapeString '"' = "\\\""
+escapeString c | c <= '\xFFFF' = escapeGeneral c
+               | otherwise = escapeGeneral lead ++ escapeGeneral trail
+                   where c' = fromEnum c - 0x010000
+                         lead = toEnum $ 0xD800 + c' `div` 0x0400
+                         trail = toEnum $ 0xDC00 + c' `mod` 0x0400
+
+-- Operator precedence of binary operators
+-- 20.2 of Dart Programming Language Specification
+-- http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf
+opPrec :: String -> Int
+opPrec "*"  = 14
+opPrec "/"  = 14
+opPrec "~/" = 14
+opPrec "%"  = 14
+opPrec "+"  = 13
+opPrec "-"  = 13
+opPrec "<<" = 12
+opPrec ">>" = 12
+opPrec "&"  = 11
+opPrec "^"  = 10
+opPrec "|"  = 9
+opPrec "<"  = 8
+opPrec ">"  = 8
+opPrec "<=" = 8
+opPrec ">=" = 8
+opPrec "==" = 7
+opPrec "!=" = 7
+opPrec "&&" = 6
+opPrec "||" = 5
+opPrec "??" = 4
+
diff --git a/src/Language/Dart/Syntax.hs b/src/Language/Dart/Syntax.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Dart/Syntax.hs
@@ -0,0 +1,1325 @@
+{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}
+
+module Language.Dart.Syntax
+  ( AnnotatedNode(..)
+  , Annotation(..)
+  , ArgumentList(..)
+  , AstNode(..)
+  , AsyncModifier(..)
+  , Block(..)
+  , CatchClause(..)
+  , ClassMember(..)
+  , Combinator(..)
+  , Comment(..)
+  , CommentReference(..)
+  , CommentType(..)
+  , CompilationUnit(..)
+  , CompilationUnitMember(..)
+  , Configuration(..)
+  , ConstructorInitializer(..)
+  , ConstructorName(..)
+  , Declaration(..)
+  , DeclaredIdentifier(..)
+  , Directive(..)
+  , DottedName(..)
+  , EnumConstantDeclaration(..)
+  , Expression(..)
+  , ExtendsClause(..)
+  , FinalConstVarOrType(..)
+  , FinalVarOrType(..)
+  , FormalParameter(..)
+  , FormalParameterList(..)
+  , FunctionBody(..)
+  , FunctionDeclaration(..)
+  , FunctionExpression(..)
+  , Identifier(..)
+  , ImplementsClause(..)
+  , InterpolationElement(..)
+  , InvocationExpression(..)
+  , Label(..)
+  , LibraryIdentifier(..)
+  , Literal(..)
+  , MapLiteralEntry(..)
+  , MethodModifier(..)
+  , NamedCompilationUnitMember(..)
+  , NamespaceDirective(..)
+  , NewOrConst(..)
+  , NormalFormalParameter(..)
+  , ParameterKind(..)
+  , PropertyKeyword(..)
+  , ScriptTag(..)
+  , SimpleIdentifier(..)
+  , SingleStringLiteral(..)
+  , Statement(..)
+  , StringLiteral(..)
+  , SwitchMember(..)
+  , Token
+  , TypeAlias(..)
+  , TypeArgumentList(..)
+  , TypedLiteral(..)
+  , TypeName(..)
+  , TypeParameter(..)
+  , TypeParameterList(..)
+  , UriBasedDirective(..)
+  , VariableDeclaration(..)
+  , VariableDeclarationList(..)
+  , WithClause(..)
+  ) where
+
+import Data.Data
+import GHC.Generics (Generic)
+
+type Token = String
+
+-- | A literal that has a type associated with it.
+--
+--      typedLiteral ::=
+--          [ListLiteral]
+--        | [MapLiteral]
+data TypedLiteral
+  -- | A literal map.
+  --
+  --      mapLiteral ::=
+  --          'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+  --          '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+  = MapLiteral Bool -- isConst
+               (Maybe TypeArgumentList) -- typeArguments
+               [MapLiteralEntry] -- entries
+  -- | A list literal.
+  --
+  --      listLiteral ::=
+  --          'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+  | ListLiteral Bool -- isConst
+                (Maybe TypeArgumentList) -- typeArguments
+                [Expression] -- elements
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node within a [StringInterpolation].
+--
+--      interpolationElement ::=
+--          [InterpolationExpression]
+--        | [InterpolationString]
+data InterpolationElement
+  -- | An expression embedded in a string interpolation.
+  --
+  --      interpolationExpression ::=
+  --          '$' [SimpleIdentifier]
+  --        | '$' '{' [Expression] '}'
+  = InterpolationExpression Expression -- expression
+  -- | A non-empty substring of an interpolated string.
+  --
+  --    interpolationString ::=
+  --        characters
+  | InterpolationString String -- value
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A single string literal expression.
+--
+--      singleStringLiteral ::=
+--          [SimpleStringLiteral]
+--        | [StringInterpolation]
+data SingleStringLiteral
+  -- | A string literal expression that does not contain any interpolations.
+  --
+  --      simpleStringLiteral ::=
+  --          rawStringLiteral
+  --        | basicStringLiteral
+  --
+  --      rawStringLiteral ::=
+  --          'r' basicStringLiteral
+  --
+  --      simpleStringLiteral ::=
+  --          multiLineStringLiteral
+  --        | singleLineStringLiteral
+  --
+  --      multiLineStringLiteral ::=
+  --          "'''" characters "'''"
+  --        | '"""' characters '"""'
+  --
+  --      singleLineStringLiteral ::=
+  --          "'" characters "'"
+  --        | '"' characters '"'
+  = SimpleStringLiteral String -- value
+  -- | A string interpolation literal.
+  --
+  --      stringInterpolation ::=
+  --          ''' [InterpolationElement]* '''
+  --        | '"' [InterpolationElement]* '"'
+  | StringInterpolation [InterpolationElement] -- elements
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+--   A string literal expression.
+--
+--      stringLiteral ::=
+--          [SimpleStringLiteral]
+--        | [AdjacentStrings]
+--        | [StringInterpolation]
+data StringLiteral
+  = SingleStringLiteral' SingleStringLiteral
+  -- | Two or more string literals that are implicitly concatenated because of being
+  --   adjacent (separated only by whitespace).
+  --
+  --   While the grammar only allows adjacent strings when all of the strings are of
+  --   the same kind (single line or multi-line), this class doesn't enforce that
+  --   restriction.
+  --
+  --      adjacentStrings ::=
+  --          [StringLiteral] [StringLiteral]+
+  | AdjacentStrings [StringLiteral] -- strings
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents a literal expression.
+--
+--      literal ::=
+--          [BooleanLiteral]
+--        | [DoubleLiteral]
+--        | [IntegerLiteral]
+--        | [ListLiteral]
+--        | [MapLiteral]
+--        | [NullLiteral]
+--        | [StringLiteral]
+data Literal
+  --   A boolean literal expression.
+  --
+  --      booleanLiteral ::=
+  --          'false' | 'true'
+  = BooleanLiteral Bool -- bool
+  --   A floating point literal expression.
+  --
+  --      doubleLiteral ::=
+  --          decimalDigit+ ('.' decimalDigit*)? exponent?
+  --        | '.' decimalDigit+ exponent?
+  --
+  --      exponent ::=
+  --          ('e' | 'E') ('+' | '-')? decimalDigit+
+  | DoubleLiteral Double -- value
+  | TypedLiteral TypedLiteral
+  -- | An integer literal expression.
+  --
+  --      integerLiteral ::=
+  --          decimalIntegerLiteral
+  --        | hexadecimalIntegerLiteral
+  --
+  --      decimalIntegerLiteral ::=
+  --          decimalDigit+
+  --
+  --      hexadecimalIntegerLiteral ::=
+  --          '0x' hexadecimalDigit+
+  --        | '0X' hexadecimalDigit+
+  | IntegerLiteral Integer -- value
+  -- | A null literal expression.
+  --
+  --      nullLiteral ::=
+  --          'null'
+  | NullLiteral
+  | StringLiteral' StringLiteral
+  -- | A symbol literal expression.
+  --
+  --      symbolLiteral ::=
+  --          '#' (operator | (identifier ('.' identifier)*))
+  | SymbolLiteral [Token] -- components
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data FinalConstVarOrType = FCVTFinal TypeName
+                         | FCVTConst TypeName
+                         | FCVTType  TypeName
+                         | FCVTVar
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data FinalVarOrType = FVTFinal TypeName
+                    | FVTType TypeName
+                    | FVTVar
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data NewOrConst = NCNew | NCConst
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | An identifier that has an initial value associated with it. Instances of this
+--   class are always children of the class [VariableDeclarationList].
+--
+--      variableDeclaration ::=
+--          [SimpleIdentifier] ('=' [Expression])?
+data VariableDeclaration = VariableDeclaration SimpleIdentifier -- name
+                           (Maybe Expression) -- initializer
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The declaration of one or more variables of the same type.
+--
+--      variableDeclarationList ::=
+--          finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+--
+--      finalConstVarOrType ::=
+--        | 'final' [TypeName]?
+--        | 'const' [TypeName]?
+--        | 'var'
+--        | [TypeName]
+data VariableDeclarationList = VariableDeclarationList (Maybe Comment) -- comment
+                                                       [Annotation] -- metadata
+                                                       FinalConstVarOrType -- kind
+                                                       [VariableDeclaration] -- variables
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The declaration of a single identifier.
+--
+--      declaredIdentifier ::=
+--          [Annotation] finalConstVarOrType [SimpleIdentifier]
+data DeclaredIdentifier = DeclaredIdentifier (Maybe Comment) -- comment
+                                             [Annotation] -- metadata
+                                             FinalConstVarOrType -- kind
+                                             SimpleIdentifier -- identifier
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The declaration of an enum constant.
+data EnumConstantDeclaration = EnumConstantDeclaration (Maybe Comment)
+                                                       [Annotation]
+                                                       SimpleIdentifier
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data PropertyKeyword = Get | Set | Empty
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A top-level declaration.
+--
+--      functionDeclaration ::=
+--          'external' functionSignature
+--        | functionSignature [FunctionBody]
+--
+--      functionSignature ::=
+--          [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+data FunctionDeclaration = FunctionDeclaration (Maybe Comment) -- comment
+                                               [Annotation] -- metadata
+                                               Bool -- isExternal
+                                               (Maybe TypeName) -- returnType
+                                               PropertyKeyword -- propertyKeyword
+                                               SimpleIdentifier -- name
+                                               FunctionExpression -- functionExpression
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The with clause in a class declaration.
+--
+--      withClause ::=
+--          'with' [TypeName] (',' [TypeName])*
+newtype WithClause = WithClause [TypeName] -- mixinTypes
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The "implements" clause in an class declaration.
+--
+--      implementsClause ::=
+--          'implements' [TypeName] (',' [TypeName])*
+newtype ImplementsClause = ImplementsClause [TypeName] -- interfaces
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The declaration of a type alias.
+--
+--      typeAlias ::=
+--          'typedef' typeAliasBody
+--
+--      typeAliasBody ::=
+--          classTypeAlias
+--        | functionTypeAlias
+data TypeAlias
+  -- | A class type alias.
+  --
+  --      classTypeAlias ::=
+  --          [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+  --
+  --      mixinApplication ::=
+  --          [TypeName] [WithClause] [ImplementsClause]? ';'
+  = ClassTypeAlias    (Maybe Comment) -- comment
+                      [Annotation] -- metadata
+                      SimpleIdentifier -- name
+                      (Maybe TypeParameterList) -- typeParameters
+                      Bool -- isAbstract
+                      TypeName -- superclass
+                      WithClause -- withClause
+                      (Maybe ImplementsClause) -- implementsClause
+  -- | A function type alias.
+  --
+  --      functionTypeAlias ::=
+  --          functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+  --
+  --      functionPrefix ::=
+  --          [TypeName]? [SimpleIdentifier]
+  | FunctionTypeAlias (Maybe Comment) -- comment
+                      [Annotation] -- metadata
+                      (Maybe TypeName) -- returnType
+                      SimpleIdentifier -- name
+                      (Maybe TypeParameterList) -- typeParameters
+                      FormalParameterList -- parameters
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that declares a single name within the scope of a compilation unit.
+data NamedCompilationUnitMember
+  = FunctionDeclaration' FunctionDeclaration
+  | TypeAlias TypeAlias
+  -- | The declaration of a class.
+  --
+  --      classDeclaration ::=
+  --          'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+  --          ([ExtendsClause] [WithClause]?)?
+  --          [ImplementsClause]?
+  --          '{' [ClassMember]* '}'
+  | ClassDeclaration (Maybe Comment) -- comment
+                     [Annotation] -- metadata
+                     Bool -- isAbstract
+                     SimpleIdentifier -- name
+                     (Maybe TypeParameterList) -- typeParameters
+                     (Maybe ExtendsClause) -- extendsClause
+                     (Maybe WithClause) -- withClause
+                     (Maybe ImplementsClause) -- implementsClause
+                     [ClassMember] -- members
+  -- | The declaration of an enumeration.
+  --
+  --      enumType ::=
+  --          metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+  | EnumDeclaration (Maybe Comment) -- comment
+                    [Annotation] -- metadata
+                    SimpleIdentifier -- name
+                    [EnumConstantDeclaration] -- constants
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that declares one or more names within the scope of a compilation
+--   unit.
+--
+--      compilationUnitMember ::=
+--          [ClassDeclaration]
+--        | [TypeAlias]
+--        | [FunctionDeclaration]
+--        | [MethodDeclaration]
+--        | [VariableDeclaration]
+--        | [VariableDeclaration]
+data CompilationUnitMember
+  -- | The declaration of one or more top-level variables of the same type.
+  --
+  --      topLevelVariableDeclaration ::=
+  --          ('final' | 'const') type? staticFinalDeclarationList ';'
+  --        | variableDeclaration ';'
+  = TopLevelVariableDeclaration (Maybe Comment) -- comment
+                                [Annotation] -- metadata
+                                VariableDeclarationList -- variableList
+  | NamedCompilationUnitMember NamedCompilationUnitMember
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data MethodModifier = Abstract | Static
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that declares a name within the scope of a class.
+data ClassMember
+  --   A constructor declaration.
+  --
+  --      constructorDeclaration ::=
+  --          constructorSignature [FunctionBody]?
+  --        | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+  --
+  --      constructorSignature ::=
+  --          'external'? constructorName formalParameterList initializerList?
+  --        | 'external'? 'factory' factoryName formalParameterList initializerList?
+  --        | 'external'? 'const'  constructorName formalParameterList initializerList?
+  --
+  --      constructorName ::=
+  --          [SimpleIdentifier] ('.' [SimpleIdentifier])?
+  --
+  --      factoryName ::=
+  --          [Identifier] ('.' [SimpleIdentifier])?
+  --
+  --      initializerList ::=
+  --          ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+  = ConstructorDeclaration (Maybe Comment) -- comment
+                           [Annotation] -- metadata
+                           Bool -- isExternal
+                           Bool -- isConst
+                           Bool -- isFactory
+                           Identifier -- returnType
+                           (Maybe SimpleIdentifier) -- name
+                           FormalParameterList -- parameters
+                           [ConstructorInitializer] -- initializers
+                           (Maybe ConstructorName) -- redirectedConstructor
+                           (Maybe FunctionBody) -- body
+  -- | A method declaration.
+  --
+  --      methodDeclaration ::=
+  --          methodSignature [FunctionBody]
+  --
+  --      methodSignature ::=
+  --          'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+  --          methodName [TypeParameterList] [FormalParameterList]
+  --
+  --      methodName ::=
+  --          [SimpleIdentifier]
+  --        | 'operator' [SimpleIdentifier]
+  | MethodDeclaration (Maybe Comment) -- comment
+                      [Annotation] -- metadata
+                      Bool -- isExternal
+                      (Maybe MethodModifier) -- methodModifier
+                      (Maybe TypeName) -- returnType
+                      PropertyKeyword
+                      Bool -- isOperator
+                      SimpleIdentifier -- name
+                      (Maybe TypeParameterList) -- typeParameters
+                      (Maybe FormalParameterList) -- parameters
+                      FunctionBody -- body
+  -- | The declaration of one or more fields of the same type.
+  --
+  --      fieldDeclaration ::=
+  --          'static'? [VariableDeclarationList] ';'
+  | FieldDeclaration  (Maybe Comment) -- comment
+                      [Annotation] -- metadata
+                      Bool -- isStatic
+                      VariableDeclarationList -- fieldList
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- |  A node that represents the declaration of one or more names. Each declared
+--    name is visible within a name scope.
+data Declaration
+  = VariableDeclaration' VariableDeclaration
+  | TypeParameter' TypeParameter
+  | ClassMember ClassMember
+  | DeclaredIdentifier' DeclaredIdentifier
+  | EnumConstantDeclaration' EnumConstantDeclaration
+  | CompilationUnitMember' CompilationUnitMember
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents a directive that impacts the namespace of a library.
+--
+--      directive ::=
+--          [ExportDirective]
+--        | [ImportDirective]
+data NamespaceDirective
+  -- | An export directive.
+  --
+  --      exportDirective ::=
+  --          [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+  = ExportDirective (Maybe Comment) -- comment
+                    [Annotation] -- metadata
+                    StringLiteral -- libraryUri
+                    [Configuration] -- configurations
+                    [Combinator] -- combinators
+  -- | An import directive.
+  --
+  --      importDirective ::=
+  --          [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+  --        | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+  | ImportDirective (Maybe Comment) -- comment
+                    [Annotation] -- metadata
+                    StringLiteral -- libraryUri
+                    [Configuration] -- configurations
+                    Bool -- isDeferred
+                    (Maybe SimpleIdentifier) -- prefix
+                    [Combinator] -- combinators
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A directive that references a URI.
+--
+--      uriBasedDirective ::=
+--          [ExportDirective]
+--        | [ImportDirective]
+--        | [PartDirective]
+data UriBasedDirective
+  = NamespaceDirective NamespaceDirective
+  -- | A part directive.
+  --
+  --      partDirective ::=
+  --          [Annotation] 'part' [StringLiteral] ';'
+  | PartDirective (Maybe Comment) -- comment
+                  [Annotation] -- metadata
+                  StringLiteral -- partUri
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents a directive.
+--
+--      directive ::=
+--          [ExportDirective]
+--        | [ImportDirective]
+--        | [LibraryDirective]
+--        | [PartDirective]
+--        | [PartOfDirective]
+data Directive
+  = UriBasedDirective UriBasedDirective
+  -- | A part-of directive.
+  --
+  --      partOfDirective ::=
+  --          [Annotation] 'part' 'of' [Identifier] ';'
+  | PartOfDirective (Maybe Comment) -- comment
+                    [Annotation] -- metadata
+                    LibraryIdentifier -- libraryName
+  -- | A library directive.
+  --
+  --      libraryDirective ::=
+  --          [Annotation] 'library' [Identifier] ';'
+  | LibraryDirective (Maybe Comment) -- comment
+                     [Annotation] -- metadata
+                     LibraryIdentifier -- name
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | An AST node that can be annotated with both a documentation comment and a
+--   list of annotations.
+data AnnotatedNode
+  = VariableDeclarationList' VariableDeclarationList
+  | Declaration' Declaration
+  | Directive Directive
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that can occur in the initializer list of a constructor declaration.
+--
+--      constructorInitializer ::=
+--          [SuperConstructorInvocation]
+--        | [ConstructorFieldInitializer]
+--        | [RedirectingConstructorInvocation]
+data ConstructorInitializer
+  -- | The invocation of a constructor in the same class from within a constructor's
+  --   initialization list.
+  --
+  --      redirectingConstructorInvocation ::=
+  --          'this' ('.' identifier)? arguments
+  = RedirectingConstructorInvocation (Maybe SimpleIdentifier) -- constructorName
+                                     ArgumentList -- argumentList
+  -- | The initialization of a field within a constructor's initialization list.
+  --
+  --      fieldInitializer ::=
+  --          ('this' '.')? [SimpleIdentifier] '=' [Expression]
+  | ConstructorFieldInitializer Bool -- explicitThis
+                                SimpleIdentifier -- fieldName
+                                Expression -- expression
+  -- | The invocation of a superclass' constructor from within a constructor's
+  --   initialization list.
+  --
+  --      superInvocation ::=
+  --          'super' ('.' [SimpleIdentifier])? [ArgumentList]
+  | SuperConstructorInvocation (Maybe SimpleIdentifier) -- constructorName
+                               ArgumentList -- argumentList
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A combinator associated with an import or export directive.
+--
+--      combinator ::=
+--          [HideCombinator]
+--        | [ShowCombinator]
+data Combinator
+  -- | A combinator that restricts the names being imported to those in a given list.
+  --
+  --      showCombinator ::=
+  --          'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+  = ShowCombinator [SimpleIdentifier] -- shownNames
+  -- | A combinator that restricts the names being imported to those that are not in
+  --   a given list.
+  --
+  --      hideCombinator ::=
+  --          'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+  | HideCombinator [SimpleIdentifier] -- hiddenNames
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A dotted name, used in a configuration within an import or export directive.
+--
+--      dottedName ::=
+--          [SimpleIdentifier] ('.' [SimpleIdentifier])*
+newtype DottedName = DottedName [SimpleIdentifier] -- components
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A configuration in either an import or export directive.
+--
+--      configuration ::=
+--          'if' '(' test ')' uri
+--
+--      test ::=
+--          dottedName ('==' stringLiteral)?
+--
+--      dottedName ::=
+--          identifier ('.' identifier)*
+data Configuration = Configuration DottedName -- name
+                                   StringLiteral -- value
+                                   StringLiteral -- libraryUri
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The "extends" clause in a class declaration.
+--
+--      extendsClause ::=
+--          'extends' [TypeName]
+newtype ExtendsClause = ExtendsClause TypeName -- superclass
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A single key/value pair in a map literal.
+--
+--      mapLiteralEntry ::=
+--          [Expression] ':' [Expression]
+data MapLiteralEntry = MapLiteralEntry Expression -- key
+                                       Expression -- value
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+newtype ScriptTag = ScriptTag Token -- scriptTag
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node in the AST structure for a Dart program.
+data AstNode
+  = SwitchMember SwitchMember
+  | Statement Statement
+  | CatchClause' CatchClause
+  | TypeNameNode TypeName
+  | TypeArgumentList' TypeArgumentList
+  | Label' Label
+  | Annotation' Annotation
+  | Comment' Comment
+  | CommentReference' CommentReference
+  | ArgumentList' ArgumentList
+  | TypeParameterList' TypeParameterList
+  | FormalParameterList' FormalParameterList
+  | AnnotatedNode' AnnotatedNode
+  | WithClause' WithClause
+  | ExtendsClause' ExtendsClause
+  | ConstructorName' ConstructorName
+  | InterpolationElement' InterpolationElement
+  | ConstructorInitializer ConstructorInitializer
+  | Combinator Combinator
+  | Configuration' Configuration
+  | DottedName' DottedName
+  --   A script tag that can optionally occur at the beginning of a compilation unit.
+  --
+  --      scriptTag ::=
+  --          '#!' (~NEWLINE)* NEWLINE
+  | ScriptTag' ScriptTag
+  -- | The "native" clause in an class declaration.
+  --
+  --      nativeClause ::=
+  --          'native' [StringLiteral]
+  | NativeClause StringLiteral -- name
+  | MapLiteralEntry' MapLiteralEntry
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data ParameterKind = Required | Positional | Named
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A formal parameter that is required (is not optional).
+--
+--      normalFormalParameter ::=
+--          [FunctionTypedFormalParameter]
+--        | [FieldFormalParameter]
+--        | [SimpleFormalParameter]
+data NormalFormalParameter
+  -- | A function-typed formal parameter.
+  --
+  --      functionSignature ::=
+  --          [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+  = FunctionTypedFormalParameter (Maybe Comment) -- comment
+                                 [Annotation] -- metadata
+                                 (Maybe TypeName) -- returnType
+                                 SimpleIdentifier -- identifier
+                                 (Maybe TypeParameterList) -- typeParameters
+                                 FormalParameterList -- parameters
+  -- | A field formal parameter.
+  --
+  --      fieldFormalParameter ::=
+  --          ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+  --          'this' '.' [SimpleIdentifier]
+  | FieldFormalParameter         (Maybe Comment) -- comment
+                                 [Annotation] -- metadata
+                                 (Maybe FinalConstVarOrType)
+                                 Bool -- explicitThis
+                                 SimpleIdentifier -- identifier
+  -- | A simple formal parameter.
+  --
+  --      simpleFormalParameter ::=
+  --          ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+  | SimpleFormalParameter        (Maybe Comment) -- comment
+                                 [Annotation] -- metadata
+                                 FinalVarOrType
+                                 SimpleIdentifier -- identifier
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node representing a parameter to a function.
+--
+--      formalParameter ::=
+--          [NormalFormalParameter]
+--        | [DefaultFormalParameter]
+data FormalParameter
+  = NormalFormalParameter' NormalFormalParameter
+  --   A formal parameter with a default value. There are two kinds of parameters
+  --   that are both represented by this class: named formal parameters and
+  --   positional formal parameters.
+  --
+  --      defaultFormalParameter ::=
+  --          [NormalFormalParameter] ('=' [Expression])?
+  --
+  --      defaultNamedParameter ::=
+  --          [NormalFormalParameter] (':' [Expression])?
+  | DefaultFormalParameter NormalFormalParameter -- parameter
+                           ParameterKind -- kind
+                           (Maybe Expression) -- defaultValue
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The formal parameter list of a method declaration, function declaration, or
+--   function type alias.
+--
+--   While the grammar requires all optional formal parameters to follow all of
+--   the normal formal parameters and at most one grouping of optional formal
+--   parameters, this class does not enforce those constraints. All parameters are
+--   flattened into a single list, which can have any or all kinds of parameters
+--   (normal, named, and positional) in any order.
+--
+--      formalParameterList ::=
+--          '(' ')'
+--        | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+--        | '(' optionalFormalParameters ')'
+--
+--      normalFormalParameters ::=
+--          [NormalFormalParameter] (',' [NormalFormalParameter])*
+--
+--      optionalFormalParameters ::=
+--          optionalPositionalFormalParameters
+--        | namedFormalParameters
+--
+--      optionalPositionalFormalParameters ::=
+--          '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+--
+--      namedFormalParameters ::=
+--          '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+newtype FormalParameterList = FormalParameterList [FormalParameter] -- parameters
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A type parameter.
+--
+--      typeParameter ::=
+--          [SimpleIdentifier] ('extends' [TypeName])?
+data TypeParameter = TypeParameter (Maybe Comment) -- comment
+                                   [Annotation] -- metadata
+                                   SimpleIdentifier -- name
+                                   (Maybe TypeName) -- bound
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | Type parameters within a declaration.
+--
+--      typeParameterList ::=
+--          '<' [TypeParameter] (',' [TypeParameter])* '>'
+newtype TypeParameterList = TypeParameterList [TypeParameter] -- typeParameters
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A list of arguments in the invocation of an executable element (that is, a
+--   function, method, or constructor).
+--
+--      argumentList ::=
+--          '(' arguments? ')'
+--
+--      arguments ::=
+--          [NamedExpression] (',' [NamedExpression])*
+--        | [Expression] (',' [Expression])* (',' [NamedExpression])*
+newtype ArgumentList = ArgumentList [Expression] -- arguments
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A reference to a Dart element that is found within a documentation comment.
+--
+--      commentReference ::=
+--          '[' 'new'? [Identifier] ']'
+data CommentReference = CommentReference Bool -- isNew
+                                         Identifier -- identifier
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data CommentType = BlockComment | DocumentationComment | EndOfLineComment
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A comment within the source code.
+--
+--      comment ::=
+--          endOfLineComment
+--        | blockComment
+--        | documentationComment
+--
+--      endOfLineComment ::=
+--          '//' (CHARACTER - EOL)* EOL
+--
+--      blockComment ::=
+--          '/--  ' CHARACTER* '&#42;/'
+--
+--      documentationComment ::=
+--          '/--  *' (CHARACTER | [CommentReference])* '&#42;/'
+--        | ('///' (CHARACTER - EOL)* EOL)+
+data Comment = Comment [Token] -- tokens
+                       CommentType -- type
+                       [CommentReference] -- references
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | An annotation that can be associated with an AST node.
+--
+--      metadata ::=
+--          annotation*
+--
+--      annotation ::=
+--          '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+data Annotation = Annotation Identifier -- name
+                             (Maybe SimpleIdentifier) -- constructorName
+                             (Maybe ArgumentList) -- arguments
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A label on either a [LabeledStatement] or a [NamedExpression].
+--
+--      label ::=
+--          [SimpleIdentifier] ':'
+newtype Label = Label SimpleIdentifier -- label
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The name of a type, which can optionally include type arguments.
+--
+--      typeName ::=
+--          [Identifier] typeArguments?
+data TypeName = TypeName Identifier -- name
+                         (Maybe TypeArgumentList) --typeArguments
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A list of type arguments.
+--
+--      typeArguments ::=
+--          '<' typeName (',' typeName)* '>'
+data TypeArgumentList = TypeArgumentList [TypeName] -- arguments
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | An element within a switch statement.
+--
+--      switchMember ::=
+--          switchCase
+--        | switchDefault
+data SwitchMember
+  -- | The default case in a switch statement.
+  --
+  --      switchDefault ::=
+  --          [SimpleIdentifier]* 'default' ':' [Statement]*
+  = SwitchDefault [Label] -- labels
+                  [Statement] -- statements
+  -- | A case in a switch statement.
+  --
+  --      switchCase ::=
+  --          [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+  | SwitchCase [Label] -- labels
+               Expression -- expression
+               [Statement] -- statements
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A catch clause within a try statement.
+--
+--      onPart ::=
+--          catchPart [Block]
+--        | 'on' type catchPart? [Block]
+--
+--      catchPart ::=
+--          'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+data CatchClause = CatchClause (Maybe TypeName) -- exceptionType
+                               SimpleIdentifier -- exceptionParameter
+                               (Maybe SimpleIdentifier) -- stackTraceParameter
+                               Block -- body
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A sequence of statements.
+--
+--      block ::=
+--          '{' statement* '}'
+data Block = Block [Statement] -- statements
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A simple identifier.
+--
+--      simpleIdentifier ::=
+--          initialCharacter internalCharacter*
+--
+--      initialCharacter ::= '_' | '$' | letter
+--
+--      internalCharacter ::= '_' | '$' | letter | digit
+newtype SimpleIdentifier = SimpleIdentifier Token -- token
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The identifier for a library.
+--
+--      libraryIdentifier ::=
+--          [SimpleIdentifier] ('.' [SimpleIdentifier])*
+newtype LibraryIdentifier = LibraryIdentifier [SimpleIdentifier] -- components
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents an identifier.
+--
+--      identifier ::=
+--          [SimpleIdentifier]
+--        | [PrefixedIdentifier]
+data Identifier
+  = SimpleIdentifier' SimpleIdentifier
+  -- | An identifier that is prefixed or an access to an object property where the
+  --   target of the property access is a simple identifier.
+  --
+  --      prefixedIdentifier ::=
+  --          [SimpleIdentifier] '.' [SimpleIdentifier]
+  | PrefixedIdentifier SimpleIdentifier -- prefix
+                       SimpleIdentifier -- identifier
+  | LibraryIdentifier' LibraryIdentifier
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+data AsyncModifier = Async | Sync | AsyncStar | SyncStar
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node representing the body of a function or method.
+--
+--      functionBody ::=
+--          [BlockFunctionBody]
+--        | [EmptyFunctionBody]
+--        | [ExpressionFunctionBody]
+data FunctionBody
+  -- | A function body that consists of a block of statements.
+  --
+  --      blockFunctionBody ::=
+  --          ('async' | 'async' '*' | 'sync' '*')? [Block]
+  = BlockFunctionBody AsyncModifier -- asyncModifier
+                      Block -- block
+  -- | An empty function body, which can only appear in constructors or abstract
+  --   methods.
+  --
+  --      emptyFunctionBody ::=
+  --          ';'
+  | EmptyFunctionBody
+  -- | A function body consisting of a single expression.
+  --
+  --      expressionFunctionBody ::=
+  --          'async'? '=>' [Expression] ';'
+  | ExpressionFunctionBody Bool -- isAsync
+                           Expression -- expression
+  -- | A function body that consists of a native keyword followed by a string
+  --   literal.
+  --
+  --      nativeFunctionBody ::=
+  --          'native' [SimpleStringLiteral] ';'
+  | NativeFunctionBody StringLiteral -- stringLiteral
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A function expression.
+--
+--      functionExpression ::=
+--          [TypeParameterList]? [FormalParameterList] [FunctionBody]
+data FunctionExpression = FunctionExpression (Maybe TypeParameterList) -- typeParameters
+                                             FormalParameterList -- parameters
+                                             FunctionBody -- body
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The name of a constructor.
+--
+--      constructorName ::=
+--          type ('.' identifier)?
+data ConstructorName = ConstructorName TypeName -- type
+                                       (Maybe SimpleIdentifier) -- name
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | The invocation of a function or method; either a
+--   [FunctionExpressionInvocation] or a [MethodInvocation].
+data InvocationExpression
+  -- | The invocation of a function resulting from evaluating an expression.
+  --   Invocations of methods and other forms of functions are represented by
+  --   [MethodInvocation] nodes. Invocations of getters and setters are represented
+  --   by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+  --
+  --      functionExpressionInvocation ::=
+  --          [Expression] [TypeArgumentList]? [ArgumentList]
+  = FunctionExpressionInvocation Expression -- function
+                                 (Maybe TypeArgumentList) -- typeArguments
+                                 ArgumentList -- argumentList
+  -- | The invocation of either a function or a method. Invocations of functions
+  --   resulting from evaluating an expression are represented by
+  --   [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
+  --   represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+  --
+  --      methodInvocation ::=
+  --          ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+  | MethodInvocation (Maybe Expression) -- target
+                     SimpleIdentifier -- methodName
+                     (Maybe TypeArgumentList) -- typeArguments
+                     ArgumentList -- argumentList
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents an expression.
+--
+--      expression ::=
+--          [AssignmentExpression]
+--        | [ConditionalExpression] cascadeSection*
+--        | [ThrowExpression]
+data Expression
+  = Literal' Literal
+  | Identifier' Identifier
+  -- | A prefix unary expression.
+  --
+  --      prefixExpression ::=
+  --          [Token] [Expression]
+  | PrefixExpression Token -- operator
+                     Expression -- operand
+  -- | A postfix unary expression.
+  --
+  --      postfixExpression ::=
+  --          [Expression] [Token]
+  | PostfixExpression Expression -- operand
+                      Token -- operator
+  -- | A binary (infix) expression.
+  --
+  --      binaryExpression ::=
+  --          [Expression] [Token] [Expression]
+  | BinaryExpression Expression -- leftOperand
+                     Token -- operator
+                     Expression -- rightOperand
+  -- | An assignment expression.
+  --
+  --      assignmentExpression ::=
+  --          [Expression] operator [Expression]
+  | AssignmentExpression Expression -- leftHandSide
+                         Token -- operator
+                         Expression -- rightHandSide
+  | FunctionExpression' FunctionExpression
+  -- | An instance creation expression.
+  --
+  --      newExpression ::=
+  --          ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+  | InstanceCreationExpression NewOrConst
+                               ConstructorName -- constructorName
+                               ArgumentList -- argumentList
+  -- | An as expression.
+  --
+  --      asExpression ::=
+  --          [Expression] 'as' [TypeName]
+  | AsExpression Expression -- expression
+                 TypeName -- type
+  -- | An is expression.
+  --
+  --      isExpression ::=
+  --          [Expression] 'is' '!'? [TypeName]
+  | IsExpression Expression -- expression
+                 Bool -- isNot
+                 TypeName -- type
+  -- | A throw expression.
+  --
+  --      throwExpression ::=
+  --          'throw' [Expression]
+  | ThrowExpression Expression -- expression
+  -- | A rethrow expression.
+  --
+  --      rethrowExpression ::=
+  --          'rethrow'
+  | RethrowExpression
+  -- | A this expression.
+  --
+  --      thisExpression ::=
+  --          'this'
+  | ThisExpression
+  -- | A super expression.
+  --
+  --      superExpression ::=
+  --          'super'
+  | SuperExpression
+  -- | A parenthesized expression.
+  --
+  --      parenthesizedExpression ::=
+  --          '(' [Expression] ')'
+  | ParenthesizedExpression Expression -- expression
+  -- | The access of a property of an object.
+  --
+  --   Note, however, that accesses to properties of objects can also be represented
+  --   as [PrefixedIdentifier] nodes in cases where the target is also a simple
+  --   identifier.
+  --
+  --      propertyAccess ::=
+  --          [Expression] '.' [SimpleIdentifier]
+  | PropertyAccess Expression -- target
+                   SimpleIdentifier -- propertyName
+  -- | An expression that has a name associated with it. They are used in method
+  --   invocations when there are named parameters.
+  --
+  --      namedExpression ::=
+  --          [Label] [Expression]
+  | NamedExpression Label -- name
+                    Expression -- expression
+  | InvocationExpression InvocationExpression
+  -- | A conditional expression.
+  --
+  --      conditionalExpression ::=
+  --          [Expression] '?' [Expression] ':' [Expression]
+  | ConditionalExpression Expression -- condition
+                          Expression -- thenExpression
+                          Expression -- elseExpression
+  -- | A sequence of cascaded expressions: expressions that share a common target.
+  --   There are three kinds of expressions that can be used in a cascade
+  --   expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
+  --
+  --      cascadeExpression ::=
+  --          [Expression] cascadeSection*
+  --
+  --      cascadeSection ::=
+  --          '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
+  --          (assignmentOperator expressionWithoutCascade)?
+  --
+  --      cascadeSelector ::=
+  --          '[ ' expression '] '
+  --        | identifier
+  | CascadeExpression Expression -- target
+                      [Expression] -- cascadeSections
+  -- | An index expression.
+  --
+  --      indexExpression ::=
+  --          [Expression] '[' [Expression] ']'
+  | IndexExpressionForCasecade Expression -- index
+  | IndexExpressionForTarget   Expression -- target
+                               Expression -- index
+  -- | An await expression.
+  --
+  --      awaitExpression ::=
+  --          'await' [Expression]
+  | AwaitExpression Expression -- expression
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A node that represents a statement.
+--
+--      statement ::=
+--          [Block]
+--        | [VariableDeclarationStatement]
+--        | [ForStatement]
+--        | [ForEachStatement]
+--        | [WhileStatement]
+--        | [DoStatement]
+--        | [SwitchStatement]
+--        | [IfStatement]
+--        | [TryStatement]
+--        | [BreakStatement]
+--        | [ContinueStatement]
+--        | [ReturnStatement]
+--        | [ExpressionStatement]
+--        | [FunctionDeclarationStatement]
+data Statement
+  = Block' Block
+  -- | A list of variables that are being declared in a context where a statement is
+  --   required.
+  --
+  --      variableDeclarationStatement ::=
+  --          [VariableDeclarationList] ';'
+  | VariableDeclarationStatement VariableDeclarationList -- variableList
+  -- | A for statement.
+  --
+  --      forStatement ::=
+  --          'for' '(' forLoopParts ')' [Statement]
+  --
+  --      forLoopParts ::=
+  --          forInitializerStatement ';' [Expression]? ';' [Expression]?
+  --
+  --      forInitializerStatement ::=
+  --          [DefaultFormalParameter]
+  --        | [Expression]?
+  | ForStatement (Maybe VariableDeclarationList) -- variableList
+                 (Maybe Expression) -- initialization
+                 (Maybe Expression) -- condition
+                 [Expression] -- updaters
+                 Statement -- body
+  -- | A for-each statement.
+  --
+  --      forEachStatement ::=
+  --          'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+  --        | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+  | ForEachStatementWithDeclaration Bool -- isAwait
+                                    DeclaredIdentifier -- loopVariable
+                                    Expression -- iterator
+                                    Statement -- body
+  | ForEachStatementWithReference   Bool -- isAwait
+                                    SimpleIdentifier -- identifier
+                                    Expression -- iterator
+                                    Statement -- body
+  -- | A while statement.
+  --
+  --      whileStatement ::=
+  --          'while' '(' [Expression] ')' [Statement]
+  | WhileStatement Expression -- condition
+                   Statement -- body
+  -- | A do statement.
+  --
+  --      doStatement ::=
+  --          'do' [Statement] 'while' '(' [Expression] ')' ';'
+  | DoStatement Statement -- body
+                Expression -- condition
+  -- | A switch statement.
+  --
+  --      switchStatement ::=
+  --          'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+  | SwitchStatement Expression -- expression
+                    [SwitchMember] -- members
+  -- | An if statement.
+  --
+  --      ifStatement ::=
+  --          'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+  | IfStatement Expression -- condition
+                Statement -- thenStatement
+                (Maybe Statement) -- elseStatement
+  -- | A try statement.
+  --
+  --      tryStatement ::=
+  --          'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+  --
+  --      finallyClause ::=
+  --          'finally' [Block]
+  | TryStatement Block -- body
+                 [CatchClause] -- catchClauses
+                 (Maybe Block) -- finallyBlock
+  --   A break statement.
+  --
+  --      breakStatement ::=
+  --          'break' [SimpleIdentifier]? ';'
+  | BreakStatement (Maybe SimpleIdentifier) -- label
+  -- | A continue statement.
+  --
+  --      continueStatement ::=
+  --          'continue' [SimpleIdentifier]? ';'
+  | ContinueStatement (Maybe SimpleIdentifier) -- label
+  -- | A return statement.
+  --
+  --      returnStatement ::=
+  --          'return' [Expression]? ';'
+  | ReturnStatement (Maybe Expression) -- expression
+  -- | An expression used as a statement.
+  --
+  --      expressionStatement ::=
+  --          [Expression]? ';'
+  | ExpressionStatement Expression -- expression
+  -- | A [FunctionDeclaration] used as a statement.
+  | FunctionDeclarationStatement FunctionDeclaration
+  -- | An assert statement.
+  --
+  --      assertStatement ::=
+  --          'assert' '(' [Expression] ')' ';'
+  | AssertStatement Expression -- condition
+                    (Maybe Expression) -- message
+  -- | A yield statement.
+  --
+  --    yieldStatement ::=
+  --        'yield' '*'? [Expression] ‘;’
+  | YieldStatement Bool -- isStar
+                   Expression -- expression
+  -- | An empty statement.
+  --
+  --      emptyStatement ::=
+  --          ';'
+  | EmptyStatement
+  -- | A statement that has a label associated with them.
+  --
+  --      labeledStatement ::=
+  --         [Label]+ [Statement]
+  | LabeledStatement [Label] -- labels
+                     Statement -- statement
+  deriving (Eq, Show, Typeable, Generic, Data)
+
+-- | A compilation unit.
+--
+--   While the grammar restricts the order of the directives and declarations
+--   within a compilation unit, this class does not enforce those restrictions.
+--   In particular, the children of a compilation unit will be visited in lexical
+--   order even if lexical order does not conform to the restrictions of the
+--   grammar.
+--
+--      compilationUnit ::=
+--          directives declarations
+--
+--      directives ::=
+--          [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+--        | [PartOfDirective]
+--
+--      namespaceDirective ::=
+--          [ImportDirective]
+--        | [ExportDirective]
+--
+--      declarations ::=
+--          [CompilationUnitMember]*
+data CompilationUnit = CompilationUnit (Maybe ScriptTag) -- scriptTag
+                                       [Directive] -- directives
+                                       [CompilationUnitMember] -- declarations
+  deriving (Eq, Show, Typeable, Generic, Data)
+
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,434 @@
+import Test.Hspec
+
+import Language.Dart.Pretty
+import Language.Dart.Syntax
+
+intExp :: Integer -> Expression
+intExp = Literal' . IntegerLiteral
+
+ident :: String -> Identifier
+ident = SimpleIdentifier' . SimpleIdentifier
+
+identExp :: String -> Expression
+identExp = Identifier' . ident
+
+tyName :: String -> TypeName
+tyName name = TypeName (ident name) Nothing
+
+strType = tyName "String"
+numType = tyName "num"
+
+formal :: TypeName -> String -> FormalParameter
+formal ty p = NormalFormalParameter' $
+  SimpleFormalParameter Nothing [] (FVTType ty) (SimpleIdentifier p)
+
+posFormal :: TypeName -> String -> FormalParameter
+posFormal ty p = DefaultFormalParameter parameter Positional Nothing
+  where parameter = (SimpleFormalParameter Nothing [] (FVTType ty) (SimpleIdentifier p))
+
+var :: String -> FormalParameter
+var p = NormalFormalParameter' $
+  SimpleFormalParameter Nothing [] FVTVar (SimpleIdentifier p)
+
+strLit :: String -> StringLiteral
+strLit = SingleStringLiteral' .  SimpleStringLiteral
+
+strLitExp :: String -> Expression
+strLitExp = Literal' . StringLiteral' . strLit
+
+nullExp :: Expression
+nullExp = Literal' NullLiteral
+
+funStmt :: String -> Statement
+funStmt name = ExpressionStatement (
+                 InvocationExpression (
+                   MethodInvocation Nothing
+                                    (SimpleIdentifier name)
+                                    Nothing
+                                    (ArgumentList [])))
+
+funStmt1 :: String -> Expression -> Statement
+funStmt1 name arg1 = ExpressionStatement (
+                       InvocationExpression (
+                         MethodInvocation Nothing
+                                          (SimpleIdentifier name)
+                                          Nothing
+                                          (ArgumentList [arg1])))
+
+prettyPrintSpec :: Spec
+prettyPrintSpec =
+  describe "prettyPrint" $ do
+    it "preserves operator precedence" $ do
+      let l = BinaryExpression (intExp 1) "+" (intExp 2)
+          r = BinaryExpression (intExp 3) "-" (intExp 2)
+          e = BinaryExpression l "*" r
+      prettyPrint e `shouldBe` "(1 + 2) * (3 - 2)"
+
+    it "prints an import directive" $ do
+      let libraryUri = strLit "package:analyzer/src/dart/ast/ast.dart"
+          as = SimpleIdentifier "a"
+          imp = ImportDirective Nothing
+                                []
+                                libraryUri
+                                []
+                                False
+                                (Just as)
+                                [ ShowCombinator [SimpleIdentifier "TypeName"]
+                                , ShowCombinator [SimpleIdentifier "ArgumentList"]
+                                ]
+      prettyPrint imp `shouldBe` "import \"package:analyzer/src/dart/ast/ast.dart\" as a show TypeName, show ArgumentList;"
+
+    it "prints a function declaration" $ do
+      let formals = FormalParameterList [formal numType "aNumber"]
+          arg = Literal' . StringLiteral' . SingleStringLiteral' $
+                  StringInterpolation [ InterpolationString "The number is "
+                                      , InterpolationExpression (identExp "aNumber")
+                                      , InterpolationString "."]
+          body = BlockFunctionBody Sync
+                                   (Block [ ExpressionStatement (
+                                             InvocationExpression (
+                                               MethodInvocation Nothing
+                                                                (SimpleIdentifier "print")
+                                                                Nothing
+                                                                (ArgumentList [arg])))])
+          funExp = FunctionExpression Nothing formals body
+          funDecl = FunctionDeclaration Nothing [] False Nothing Empty (SimpleIdentifier "printNumber") funExp
+      prettyPrint funDecl `shouldBe` "printNumber(num aNumber)\n\
+                                     \{\n\
+                                     \  print(\"The number is ${aNumber}.\");\n\
+                                     \}"
+
+    it "prints an optional position parameter" $ do
+      let formals = FormalParameterList [formal strType "from", formal strType "msg", posFormal strType "device"]
+          str1 = Literal' . StringLiteral' . SingleStringLiteral' $
+                  StringInterpolation [ InterpolationExpression (identExp "from")
+                                      , InterpolationString " says "
+                                      , InterpolationExpression (identExp "msg")
+                                      ]
+          str2 = Literal' . StringLiteral' . SingleStringLiteral' $
+                  StringInterpolation [ InterpolationExpression (identExp "result")
+                                      , InterpolationString " with a "
+                                      , InterpolationExpression (identExp "device")
+                                      ]
+          body = BlockFunctionBody Sync
+                                   (Block [ VariableDeclarationStatement (
+                                              VariableDeclarationList Nothing
+                                                                      []
+                                                                      FCVTVar
+                                                                      [VariableDeclaration (SimpleIdentifier "result") (Just str1)])
+                                          , IfStatement (BinaryExpression (identExp "device") "!=" nullExp)
+                                                        (Block' (Block [ ExpressionStatement (
+                                                                          AssignmentExpression (identExp "result") "=" str2)]))
+                                                        Nothing
+                                          , ReturnStatement (Just (identExp "result"))
+                                          ])
+          funExp = FunctionExpression Nothing formals body
+          funDecl = FunctionDeclaration Nothing [] False (Just strType) Empty (SimpleIdentifier "say") funExp
+      prettyPrint funDecl `shouldBe` "String say(String from, String msg, [String device])\n\
+                                     \{\n\
+                                     \  var result = \"${from} says ${msg}\";\n\
+                                     \  if (device != null)\n\
+                                     \  {\n\
+                                     \    result = \"${result} with a ${device}\";\n\
+                                     \  }\n\
+                                     \  return result;\n\
+                                     \}"
+
+    it "prints an expression function" $ do
+      let body = ExpressionFunctionBody False (
+                  ConditionalExpression (BinaryExpression (identExp "msg") "==" nullExp)
+                                        (InvocationExpression
+                                          (MethodInvocation (Just SuperExpression)
+                                                            (SimpleIdentifier "toString")
+                                                            Nothing
+                                                            (ArgumentList [])))
+                                        (identExp "msg"))
+
+          funExp = FunctionExpression Nothing (FormalParameterList []) body
+          funDecl = FunctionDeclaration Nothing [] False (Just strType) Empty (SimpleIdentifier "toString") funExp
+      prettyPrint funDecl `shouldBe` "String toString() => msg == null ? super.toString() : msg;"
+
+    it "prints an enum" $ do
+      let enumConstDecls = [ EnumConstantDeclaration Nothing [] (SimpleIdentifier "red")
+                           , EnumConstantDeclaration Nothing [] (SimpleIdentifier "green")
+                           , EnumConstantDeclaration Nothing [] (SimpleIdentifier "blue")
+                           ]
+          enumDecl = EnumDeclaration Nothing [] (SimpleIdentifier "Color") enumConstDecls
+      prettyPrint enumDecl `shouldBe` "enum Color\n\
+                                      \{\n\
+                                      \  red,\n\
+                                      \  green,\n\
+                                      \  blue\n\
+                                      \}"
+
+    it "prints a for loop" $ do
+      let variableList = VariableDeclarationList Nothing
+                                                 []
+                                                 FCVTVar
+                                                 [VariableDeclaration (SimpleIdentifier "i") (Just (intExp 0))]
+          condition = BinaryExpression (identExp "i") "<" (intExp 5)
+          updater = PostfixExpression (identExp "i") "++"
+          body = (Block' (Block [ ExpressionStatement (
+                                    InvocationExpression (
+                                      MethodInvocation (Just (identExp "message"))
+                                                       (SimpleIdentifier "write")
+                                                       Nothing
+                                                       (ArgumentList [strLitExp "!"])))]))
+          forLoop = ForStatement (Just variableList)
+                                 Nothing
+                                 (Just condition)
+                                 [updater]
+                                 body
+      prettyPrint forLoop `shouldBe` "for (var i = 0; i < 5; i++)\n\
+                                     \{\n\
+                                     \  message.write(\"!\");\n\
+                                     \}"
+
+    it "prints a list literal" $ do
+      let litExp = Literal' . TypedLiteral $ ListLiteral False Nothing [intExp 0, intExp 1, intExp 2]
+      prettyPrint litExp `shouldBe` "[0, 1, 2]"
+
+    it "prints parameterized types" $ do
+      let consName = ConstructorName (TypeName (SimpleIdentifier' (SimpleIdentifier "Map"))
+                                               (Just (TypeArgumentList [tyName "int", tyName "View"])))
+                                     Nothing
+      let exp = InstanceCreationExpression NCNew consName (ArgumentList [])
+      prettyPrint exp `shouldBe` "new Map<int, View>()"
+
+    it "prints a switch statement" $ do
+      let switchMembers = [ SwitchCase [] (strLitExp "CLOSED") [funStmt "executeClosed", (BreakStatement Nothing)]
+                          , SwitchCase [] (strLitExp "PENDING") [funStmt "executePending", (BreakStatement Nothing)]
+                          , SwitchCase [] (strLitExp "APPROVED") [funStmt "executeApproved", (BreakStatement Nothing)]
+                          , SwitchCase [] (strLitExp "DENIED") [funStmt "executeDenied", (BreakStatement Nothing)]
+                          , SwitchCase [] (strLitExp "OPEN") [funStmt "executeOpen", (BreakStatement Nothing)]
+                          , SwitchDefault [] [funStmt "executeUnknown"]
+                          ]
+          switch = SwitchStatement (identExp "command") switchMembers
+      prettyPrint switch `shouldBe` "switch (command)\n\
+                                    \{\n\
+                                    \  case \"CLOSED\":\n\
+                                    \    executeClosed();\n\
+                                    \    break;\n\
+                                    \  case \"PENDING\":\n\
+                                    \    executePending();\n\
+                                    \    break;\n\
+                                    \  case \"APPROVED\":\n\
+                                    \    executeApproved();\n\
+                                    \    break;\n\
+                                    \  case \"DENIED\":\n\
+                                    \    executeDenied();\n\
+                                    \    break;\n\
+                                    \  case \"OPEN\":\n\
+                                    \    executeOpen();\n\
+                                    \    break;\n\
+                                    \  default:\n\
+                                    \    executeUnknown();\n\
+                                    \}"
+
+    it "prints a try statement" $ do
+      let arg = Literal' . StringLiteral' . SingleStringLiteral' $
+                  StringInterpolation [ InterpolationString "Error: "
+                                      , InterpolationExpression (identExp "e")
+                                      ]
+          try = TryStatement (Block [funStmt "breedMoreLlamas"])
+                             [CatchClause Nothing (SimpleIdentifier "e") Nothing (Block [funStmt1 "print" arg])]
+                             (Just (Block [funStmt "cleanLlamaStalls"]))
+      prettyPrint try `shouldBe` "try\n\
+                                 \{\n\
+                                 \  breedMoreLlamas();\n\
+                                 \}\n\
+                                 \catch (e)\n\
+                                 \{\n\
+                                 \  print(\"Error: ${e}\");\n\
+                                 \}\n\
+                                 \finally\n\
+                                 \{\n\
+                                 \  cleanLlamaStalls();\n\
+                                 \}"
+
+    it "prints a constructor" $ do
+      let varDeclList ty name = VariableDeclarationList Nothing
+                                                        []
+                                                        (FCVTType (tyName ty))
+                                                        [VariableDeclaration (SimpleIdentifier name) Nothing]
+
+          returnType = SimpleIdentifier' (SimpleIdentifier "Point")
+          consFormals1 = FormalParameterList [ NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "x"))
+                                             , NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "y"))
+                                             ]
+          consFormals2 = FormalParameterList [ NormalFormalParameter' (
+                                                 FieldFormalParameter Nothing
+                                                                      []
+                                                                      (Just (FCVTType (tyName "Map")))
+                                                                      False
+                                                                      (SimpleIdentifier "json"))
+                                             ]
+          methodFormals = FormalParameterList [ NormalFormalParameter' (
+                                                  FieldFormalParameter Nothing
+                                                                       []
+                                                                       (Just (FCVTType (tyName "Point")))
+                                                                       False
+                                                                       (SimpleIdentifier "other"))
+                                              ]
+          consBody = BlockFunctionBody Sync
+                                   (Block [ ExpressionStatement (
+                                              AssignmentExpression (identExp "x")
+                                                                   "="
+                                                                   (IndexExpressionForTarget (identExp "json") (strLitExp "x")))
+                                          , ExpressionStatement (
+                                              AssignmentExpression (identExp "y")
+                                                                   "="
+                                                                   (IndexExpressionForTarget (identExp "json") (strLitExp "y")))
+                                          ])
+          exp1 = BinaryExpression (identExp "x") "-" (PropertyAccess (identExp "other") (SimpleIdentifier "x"))
+          exp2 = BinaryExpression (identExp "y") "-" (PropertyAccess (identExp "other") (SimpleIdentifier "y"))
+          methodBody = BlockFunctionBody Sync
+                                   (Block [ VariableDeclarationStatement (
+                                              VariableDeclarationList Nothing
+                                                                      []
+                                                                      FCVTVar
+                                                                      [VariableDeclaration (SimpleIdentifier "dx") (Just exp1)])
+                                          , VariableDeclarationStatement (
+                                              VariableDeclarationList Nothing
+                                                                      []
+                                                                      FCVTVar
+                                                                      [VariableDeclaration (SimpleIdentifier "dy") (Just exp2)])
+                                          , ReturnStatement (Just (
+                                              InvocationExpression (
+                                                MethodInvocation Nothing
+                                                                 (SimpleIdentifier "sqrt")
+                                                                 Nothing
+                                                                 (ArgumentList [BinaryExpression (BinaryExpression (identExp "dx") "*" (identExp "dx"))
+                                                                                                 "+"
+                                                                                                 (BinaryExpression (identExp "dy") "*" (identExp "dy"))]))))
+                                          ])
+          classMembers = [ FieldDeclaration Nothing [] False (varDeclList "num" "x")
+                         , FieldDeclaration Nothing [] False (varDeclList "num" "y")
+                         , ConstructorDeclaration Nothing [] False False False returnType Nothing consFormals1 [] Nothing Nothing
+                         , ConstructorDeclaration Nothing [] False False False returnType (Just (SimpleIdentifier "fromJson")) consFormals2 [] Nothing (Just consBody)
+                         , MethodDeclaration Nothing [] False Nothing (Just (tyName "num")) Empty False (SimpleIdentifier "distanceTo") Nothing (Just methodFormals) methodBody
+                         ]
+          clazz = ClassDeclaration Nothing
+                                   []
+                                   False
+                                   (SimpleIdentifier "Point")
+                                   Nothing
+                                   Nothing
+                                   Nothing
+                                   Nothing
+                                   classMembers
+      prettyPrint clazz `shouldBe` "class Point\n\
+                                   \{\n\
+                                   \  num x;\n\
+                                   \  num y;\n\
+                                   \  Point(this.x, this.y);\n\
+                                   \  Point.fromJson(Map json)\n\
+                                   \  {\n\
+                                   \    x = json[\"x\"];\n\
+                                   \    y = json[\"y\"];\n\
+                                   \  }\n\
+                                   \  num distanceTo(Point other)\n\
+                                   \  {\n\
+                                   \    var dx = x - other.x;\n\
+                                   \    var dy = y - other.y;\n\
+                                   \    return sqrt(dx * dx + dy * dy);\n\
+                                   \  }\n\
+                                   \}"
+
+    it "prints the initializer lists of a constructor" $ do
+      let varDeclList ty name = VariableDeclarationList Nothing
+                                                        []
+                                                        (FCVTType (tyName ty))
+                                                        [VariableDeclaration (SimpleIdentifier name) Nothing]
+          returnType = SimpleIdentifier' (SimpleIdentifier "Point")
+          formals = FormalParameterList [ NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "x"))
+                                        , NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "y"))
+                                        ]
+          exp = InvocationExpression (
+                 MethodInvocation Nothing
+                                  (SimpleIdentifier "sqrt")
+                                  Nothing
+                                  (ArgumentList [BinaryExpression (BinaryExpression (identExp "x") "*" (identExp "x"))
+                                                                  "+"
+                                                                  (BinaryExpression (identExp "y") "*" (identExp "y"))]))
+          classMembers = [ FieldDeclaration Nothing [] False (varDeclList "num" "x")
+                         , FieldDeclaration Nothing [] False (varDeclList "num" "y")
+                         , FieldDeclaration Nothing [] False (varDeclList "num" "distanceFromOrigin")
+                         , ConstructorDeclaration Nothing
+                                                  []
+                                                  False
+                                                  False
+                                                  False
+                                                  returnType
+                                                  Nothing
+                                                  formals
+                                                  [ ConstructorFieldInitializer False (SimpleIdentifier "x") (identExp "x")
+                                                  , ConstructorFieldInitializer False (SimpleIdentifier "y") (identExp "y")
+                                                  , ConstructorFieldInitializer False (SimpleIdentifier "distanceFromOrigin") exp
+                                                  ]
+                                                  Nothing
+                                                  Nothing
+                         ]
+          clazz = ClassDeclaration Nothing
+                                   []
+                                   False
+                                   (SimpleIdentifier "Point")
+                                   Nothing
+                                   Nothing
+                                   Nothing
+                                   Nothing
+                                   classMembers
+
+      prettyPrint clazz `shouldBe` "class Point\n\
+                                   \{\n\
+                                   \  num x;\n\
+                                   \  num y;\n\
+                                   \  num distanceFromOrigin;\n\
+                                   \  Point(this.x, this.y) : x = x,\n\
+                                   \                          y = y,\n\
+                                   \                          distanceFromOrigin = sqrt(x * x + y * y);\n\
+                                   \}"
+
+    it "prints the implement clause" $ do
+      let implements = ImplementsClause [tyName "Comparable", tyName "Location"]
+          clazz = ClassDeclaration Nothing
+                                   []
+                                   False
+                                   (SimpleIdentifier "Point")
+                                   Nothing
+                                   Nothing
+                                   Nothing
+                                   (Just implements)
+                                   []
+      prettyPrint clazz `shouldBe` "class Point implements Comparable, Location\n\
+                                  \{\n\
+                                  \}"
+
+    it "prints the metadata" $ do
+      let annotation = Annotation (SimpleIdentifier' (SimpleIdentifier "override")) Nothing Nothing
+          methodFormals = FormalParameterList [ NormalFormalParameter' (
+                                                  FieldFormalParameter Nothing
+                                                                       []
+                                                                       (Just (FCVTType (tyName "Invocation")))
+                                                                       False
+                                                                       (SimpleIdentifier "mirror"))
+                                              ]
+          methodDecl = MethodDeclaration Nothing
+                                         [annotation]
+                                         False
+                                         Nothing
+                                         (Just (tyName "void"))
+                                         Empty
+                                         False
+                                         (SimpleIdentifier "noSuchMethod")
+                                         Nothing
+                                         (Just methodFormals)
+                                         (BlockFunctionBody Sync (Block []))
+      prettyPrint methodDecl `shouldBe` "@override\n\
+                                        \void noSuchMethod(Invocation mirror)\n\
+                                        \{\n\
+                                        \}"
+
+main :: IO ()
+main = hspec $ do
+  prettyPrintSpec
