purescript-cst 0.1.1.0 → 0.2.0.0
raw patch · 59 files changed
+4590/−780 lines, 59 filesdep +aesondep +deepseqdep +microlensdep −purescript-astdep −purescript-cstdep −tasty
Dependencies added: aeson, deepseq, microlens, mtl, protolude, serialise, vector
Dependencies removed: purescript-ast, purescript-cst, tasty, tasty-golden, tasty-quickcheck
Files
- README.md +9/−3
- purescript-cst.cabal +35/−45
- src/Control/Monad/Supply.hs +31/−0
- src/Control/Monad/Supply/Class.hs +33/−0
- src/Language/PureScript/AST.hs +14/−0
- src/Language/PureScript/AST/Binders.hs +159/−0
- src/Language/PureScript/AST/Declarations.hs +843/−0
- src/Language/PureScript/AST/Declarations/ChainId.hs +20/−0
- src/Language/PureScript/AST/Exported.hs +156/−0
- src/Language/PureScript/AST/Literals.hs +38/−0
- src/Language/PureScript/AST/Operators.hs +60/−0
- src/Language/PureScript/AST/SourcePos.hs +118/−0
- src/Language/PureScript/AST/Traversals.hs +681/−0
- src/Language/PureScript/CST/Convert.hs +63/−13
- src/Language/PureScript/CST/Errors.hs +3/−3
- src/Language/PureScript/CST/Flatten.hs +5/−6
- src/Language/PureScript/CST/Lexer.hs +15/−18
- src/Language/PureScript/CST/Monad.hs +6/−6
- src/Language/PureScript/CST/Parser.y +7/−3
- src/Language/PureScript/CST/Positions.hs +6/−6
- src/Language/PureScript/CST/Types.hs +1/−2
- src/Language/PureScript/CST/Utils.hs +6/−6
- src/Language/PureScript/Comments.hs +24/−0
- src/Language/PureScript/Constants/Prim.hs +183/−0
- src/Language/PureScript/Crash.hs +25/−0
- src/Language/PureScript/Environment.hs +630/−0
- src/Language/PureScript/Label.hs +21/−0
- src/Language/PureScript/Names.hs +255/−0
- src/Language/PureScript/PSString.hs +239/−0
- src/Language/PureScript/Roles.hs +43/−0
- src/Language/PureScript/Traversals.hs +27/−0
- src/Language/PureScript/TypeClassDictionaries.hs +46/−0
- src/Language/PureScript/Types.hs +788/−0
- tests/Main.hs +0/−28
- tests/TestCst.hs +0/−227
- tests/purs/layout/AdoIn.out +0/−20
- tests/purs/layout/AdoIn.purs +0/−19
- tests/purs/layout/CaseGuards.out +0/−54
- tests/purs/layout/CaseGuards.purs +0/−53
- tests/purs/layout/CaseWhere.out +0/−13
- tests/purs/layout/CaseWhere.purs +0/−12
- tests/purs/layout/ClassHead.out +0/−11
- tests/purs/layout/ClassHead.purs +0/−10
- tests/purs/layout/Commas.out +0/−23
- tests/purs/layout/Commas.purs +0/−22
- tests/purs/layout/Delimiter.out +0/−14
- tests/purs/layout/Delimiter.purs +0/−13
- tests/purs/layout/DoLet.out +0/−16
- tests/purs/layout/DoLet.purs +0/−15
- tests/purs/layout/DoOperator.out +0/−9
- tests/purs/layout/DoOperator.purs +0/−8
- tests/purs/layout/DoWhere.out +0/−7
- tests/purs/layout/DoWhere.purs +0/−6
- tests/purs/layout/IfThenElseDo.out +0/−11
- tests/purs/layout/IfThenElseDo.purs +0/−10
- tests/purs/layout/InstanceChainElse.out +0/−5
- tests/purs/layout/InstanceChainElse.purs +0/−4
- tests/purs/layout/LetGuards.out +0/−30
- tests/purs/layout/LetGuards.purs +0/−29
README.md view
@@ -1,6 +1,6 @@ # purescript-cst -Defines the surface syntax of the PureScript Programming Language.+The parser for the PureScript programming language. ## Compiler compatibility @@ -8,5 +8,11 @@ | `purescript` | `purescript-cst` | | --- | --- |-| `0.14.0` | `0.1.0.0` |-| `0.14.1` | `0.1.1.0` |+| 0.14.2 | 0.2.0.0 |++Before v0.14.2, there was a third package, `purescript-ast`. In v0.14.2, `purescript-ast` was merged into `purescript-cst`.++| `purescript` | `purescript-cst` | `purescript-ast` |+| --- | --- | --- |+| 0.14.1 | 0.1.1.0 | 0.1.1.0 |+| 0.14.0 | 0.1.0.0 | 0.1.0.0 |
purescript-cst.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: purescript-cst-version: 0.1.1.0+version: 0.2.0.0 license: BSD-3-Clause license-file: LICENSE copyright:@@ -14,13 +14,10 @@ homepage: http://www.purescript.org/ bug-reports: https://github.com/purescript/purescript/issues synopsis: PureScript Programming Language Concrete Syntax Tree-description: The surface syntax of the PureScript Programming Language.+description: The parser for the PureScript programming language. category: Language build-type: Simple-extra-source-files:- tests/purs/**/*.out- tests/purs/**/*.purs- README.md+extra-source-files: README.md source-repository head type: git@@ -28,6 +25,17 @@ library exposed-modules:+ Control.Monad.Supply+ Control.Monad.Supply.Class+ Language.PureScript.AST+ Language.PureScript.AST.Binders+ Language.PureScript.AST.Declarations+ Language.PureScript.AST.Declarations.ChainId+ Language.PureScript.AST.Exported+ Language.PureScript.AST.Literals+ Language.PureScript.AST.Operators+ Language.PureScript.AST.SourcePos+ Language.PureScript.AST.Traversals Language.PureScript.CST.Convert Language.PureScript.CST.Errors Language.PureScript.CST.Flatten@@ -41,6 +49,17 @@ Language.PureScript.CST.Traversals.Type Language.PureScript.CST.Types Language.PureScript.CST.Utils+ Language.PureScript.Comments+ Language.PureScript.Constants.Prim+ Language.PureScript.Crash+ Language.PureScript.Environment+ Language.PureScript.Label+ Language.PureScript.Names+ Language.PureScript.PSString+ Language.PureScript.Roles+ Language.PureScript.Traversals+ Language.PureScript.TypeClassDictionaries+ Language.PureScript.Types build-tool-depends: happy:happy ==1.20.0 hs-source-dirs: src@@ -62,49 +81,20 @@ ghc-options: -Wall build-depends:- array >=0.5.4.0 && <0.6,- base >=4.14.1.0 && <4.15,- containers >=0.6.2.1 && <0.7,- dlist >=0.8.0.8 && <0.9,- purescript-ast ==0.1.1.0,- scientific >=0.3.6.2 && <0.4,- semigroups >=0.19.1 && <0.20,- text >=1.2.4.1 && <1.3--test-suite tests- type: exitcode-stdio-1.0- main-is: Main.hs- build-tool-depends: happy:happy ==1.20.0- hs-source-dirs: tests- other-modules:- TestCst- Paths_purescript_cst-- default-language: Haskell2010- default-extensions:- BangPatterns ConstraintKinds DataKinds DefaultSignatures- DeriveFunctor DeriveFoldable DeriveTraversable DeriveGeneric- DerivingStrategies EmptyDataDecls FlexibleContexts- FlexibleInstances GeneralizedNewtypeDeriving KindSignatures- LambdaCase MultiParamTypeClasses NamedFieldPuns NoImplicitPrelude- PatternGuards PatternSynonyms RankNTypes RecordWildCards- OverloadedStrings ScopedTypeVariables TupleSections TypeFamilies- ViewPatterns-- ghc-options: -Wall- build-depends:+ aeson >=1.5.6.0 && <1.6, array >=0.5.4.0 && <0.6, base >=4.14.1.0 && <4.15,+ base-compat >=0.11.2 && <0.12,+ bytestring >=0.10.12.0 && <0.11, containers >=0.6.2.1 && <0.7,+ deepseq >=1.4.4.0 && <1.5, dlist >=0.8.0.8 && <0.9,- purescript-ast ==0.1.1.0,+ filepath >=1.4.2.1 && <1.5,+ microlens >=0.4.11.2 && <0.5,+ mtl >=2.2.2 && <2.3,+ protolude >=0.3.0 && <0.4, scientific >=0.3.6.2 && <0.4, semigroups >=0.19.1 && <0.20, text >=1.2.4.1 && <1.3,- base-compat >=0.11.2 && <0.12,- purescript-cst -any,- bytestring >=0.10.12.0 && <0.11,- filepath >=1.4.2.1 && <1.5,- tasty >=1.2.3 && <1.3,- tasty-golden >=2.3.3.2 && <2.4,- tasty-quickcheck >=0.10.1.2 && <0.11+ serialise >=0.2.3.0 && <0.3,+ vector >=0.12.1.2 && <0.13
+ src/Control/Monad/Supply.hs view
@@ -0,0 +1,31 @@+-- |+-- Fresh variable supply+--+module Control.Monad.Supply where++import Prelude.Compat++import Control.Applicative+import Control.Monad.Error.Class (MonadError(..))+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Writer++import Data.Functor.Identity++newtype SupplyT m a = SupplyT { unSupplyT :: StateT Integer m a }+ deriving (Functor, Applicative, Monad, MonadTrans, MonadError e, MonadWriter w, MonadReader r, Alternative, MonadPlus)++runSupplyT :: Integer -> SupplyT m a -> m (a, Integer)+runSupplyT n = flip runStateT n . unSupplyT++evalSupplyT :: (Functor m) => Integer -> SupplyT m a -> m a+evalSupplyT n = fmap fst . runSupplyT n++type Supply = SupplyT Identity++runSupply :: Integer -> Supply a -> (a, Integer)+runSupply n = runIdentity . runSupplyT n++evalSupply :: Integer -> Supply a -> a+evalSupply n = runIdentity . evalSupplyT n
+ src/Control/Monad/Supply/Class.hs view
@@ -0,0 +1,33 @@+-- |+-- A class for monads supporting a supply of fresh names+--++module Control.Monad.Supply.Class where++import Prelude.Compat++import Control.Monad.Supply+import Control.Monad.State+import Control.Monad.Writer+import Data.Text (Text, pack)++class Monad m => MonadSupply m where+ fresh :: m Integer+ peek :: m Integer+ default fresh :: (MonadTrans t, MonadSupply n, m ~ t n) => m Integer+ fresh = lift fresh+ default peek :: (MonadTrans t, MonadSupply n, m ~ t n) => m Integer+ peek = lift peek++instance Monad m => MonadSupply (SupplyT m) where+ fresh = SupplyT $ do+ n <- get+ put (n + 1)+ return n+ peek = SupplyT get++instance MonadSupply m => MonadSupply (StateT s m)+instance (Monoid w, MonadSupply m) => MonadSupply (WriterT w m)++freshName :: MonadSupply m => m Text+freshName = fmap (("$" <> ) . pack . show) fresh
+ src/Language/PureScript/AST.hs view
@@ -0,0 +1,14 @@+-- |+-- The initial PureScript AST+--+module Language.PureScript.AST (+ module AST+) where++import Language.PureScript.AST.Binders as AST+import Language.PureScript.AST.Declarations as AST+import Language.PureScript.AST.Exported as AST+import Language.PureScript.AST.Literals as AST+import Language.PureScript.AST.Operators as AST+import Language.PureScript.AST.SourcePos as AST+import Language.PureScript.AST.Traversals as AST
+ src/Language/PureScript/AST/Binders.hs view
@@ -0,0 +1,159 @@+-- |+-- Case binders+--+module Language.PureScript.AST.Binders where++import Prelude.Compat++import Language.PureScript.AST.SourcePos+import Language.PureScript.AST.Literals+import Language.PureScript.Names+import Language.PureScript.Comments+import Language.PureScript.Types++-- |+-- Data type for binders+--+data Binder+ -- |+ -- Wildcard binder+ --+ = NullBinder+ -- |+ -- A binder which matches a literal+ --+ | LiteralBinder SourceSpan (Literal Binder)+ -- |+ -- A binder which binds an identifier+ --+ | VarBinder SourceSpan Ident+ -- |+ -- A binder which matches a data constructor+ --+ | ConstructorBinder SourceSpan (Qualified (ProperName 'ConstructorName)) [Binder]+ -- |+ -- A operator alias binder. During the rebracketing phase of desugaring,+ -- this data constructor will be removed.+ --+ | OpBinder SourceSpan (Qualified (OpName 'ValueOpName))+ -- |+ -- Binary operator application. During the rebracketing phase of desugaring,+ -- this data constructor will be removed.+ --+ | BinaryNoParensBinder Binder Binder Binder+ -- |+ -- Explicit parentheses. During the rebracketing phase of desugaring, this+ -- data constructor will be removed.+ --+ -- Note: although it seems this constructor is not used, it _is_ useful,+ -- since it prevents certain traversals from matching.+ --+ | ParensInBinder Binder+ -- |+ -- A binder which binds its input to an identifier+ --+ | NamedBinder SourceSpan Ident Binder+ -- |+ -- A binder with source position information+ --+ | PositionedBinder SourceSpan [Comment] Binder+ -- |+ -- A binder with a type annotation+ --+ | TypedBinder SourceType Binder+ deriving (Show)++-- Manual Eq and Ord instances for `Binder` were added on 2018-03-05. Comparing+-- the `SourceSpan` values embedded in some of the data constructors of `Binder`+-- was expensive. This made exhaustiveness checking observably slow for code+-- such as the `explode` function in `test/purs/passing/LargeSumTypes.purs`.+-- Custom instances were written to skip comparing the `SourceSpan` values. Only+-- the `Ord` instance was needed for the speed-up, but I did not want the `Eq`+-- to have mismatched behavior.+instance Eq Binder where+ NullBinder == NullBinder =+ True+ (LiteralBinder _ lb) == (LiteralBinder _ lb') =+ lb == lb'+ (VarBinder _ ident) == (VarBinder _ ident') =+ ident == ident'+ (ConstructorBinder _ qpc bs) == (ConstructorBinder _ qpc' bs') =+ qpc == qpc' && bs == bs'+ (OpBinder _ qov) == (OpBinder _ qov') =+ qov == qov'+ (BinaryNoParensBinder b1 b2 b3) == (BinaryNoParensBinder b1' b2' b3') =+ b1 == b1' && b2 == b2' && b3 == b3'+ (ParensInBinder b) == (ParensInBinder b') =+ b == b'+ (NamedBinder _ ident b) == (NamedBinder _ ident' b') =+ ident == ident' && b == b'+ (PositionedBinder _ comments b) == (PositionedBinder _ comments' b') =+ comments == comments' && b == b'+ (TypedBinder ty b) == (TypedBinder ty' b') =+ ty == ty' && b == b'+ _ == _ = False++instance Ord Binder where+ compare NullBinder NullBinder = EQ+ compare (LiteralBinder _ lb) (LiteralBinder _ lb') =+ compare lb lb'+ compare (VarBinder _ ident) (VarBinder _ ident') =+ compare ident ident'+ compare (ConstructorBinder _ qpc bs) (ConstructorBinder _ qpc' bs') =+ compare qpc qpc' <> compare bs bs'+ compare (OpBinder _ qov) (OpBinder _ qov') =+ compare qov qov'+ compare (BinaryNoParensBinder b1 b2 b3) (BinaryNoParensBinder b1' b2' b3') =+ compare b1 b1' <> compare b2 b2' <> compare b3 b3'+ compare (ParensInBinder b) (ParensInBinder b') =+ compare b b'+ compare (NamedBinder _ ident b) (NamedBinder _ ident' b') =+ compare ident ident' <> compare b b'+ compare (PositionedBinder _ comments b) (PositionedBinder _ comments' b') =+ compare comments comments' <> compare b b'+ compare (TypedBinder ty b) (TypedBinder ty' b') =+ compare ty ty' <> compare b b'+ compare binder binder' =+ compare (orderOf binder) (orderOf binder')+ where+ orderOf :: Binder -> Int+ orderOf NullBinder = 0+ orderOf LiteralBinder{} = 1+ orderOf VarBinder{} = 2+ orderOf ConstructorBinder{} = 3+ orderOf OpBinder{} = 4+ orderOf BinaryNoParensBinder{} = 5+ orderOf ParensInBinder{} = 6+ orderOf NamedBinder{} = 7+ orderOf PositionedBinder{} = 8+ orderOf TypedBinder{} = 9++-- |+-- Collect all names introduced in binders in an expression+--+binderNames :: Binder -> [Ident]+binderNames = map snd . binderNamesWithSpans++binderNamesWithSpans :: Binder -> [(SourceSpan, Ident)]+binderNamesWithSpans = go []+ where+ go ns (LiteralBinder _ b) = lit ns b+ go ns (VarBinder ss name) = (ss, name) : ns+ go ns (ConstructorBinder _ _ bs) = foldl go ns bs+ go ns (BinaryNoParensBinder b1 b2 b3) = foldl go ns [b1, b2, b3]+ go ns (ParensInBinder b) = go ns b+ go ns (NamedBinder ss name b) = go ((ss, name) : ns) b+ go ns (PositionedBinder _ _ b) = go ns b+ go ns (TypedBinder _ b) = go ns b+ go ns _ = ns+ lit ns (ObjectLiteral bs) = foldl go ns (map snd bs)+ lit ns (ArrayLiteral bs) = foldl go ns bs+ lit ns _ = ns+++isIrrefutable :: Binder -> Bool+isIrrefutable NullBinder = True+isIrrefutable (VarBinder _ _) = True+isIrrefutable (PositionedBinder _ _ b) = isIrrefutable b+isIrrefutable (TypedBinder _ b) = isIrrefutable b+isIrrefutable _ = False
+ src/Language/PureScript/AST/Declarations.hs view
@@ -0,0 +1,843 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Data types for modules and declarations+--+module Language.PureScript.AST.Declarations where++import Prelude.Compat+import Protolude.Exceptions (hush)++import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import Data.Functor.Identity++import Data.Aeson.TH+import qualified Data.Map as M+import Data.Text (Text)+import qualified Data.List.NonEmpty as NEL+import GHC.Generics (Generic)++import Language.PureScript.AST.Binders+import Language.PureScript.AST.Literals+import Language.PureScript.AST.Operators+import Language.PureScript.AST.SourcePos+import Language.PureScript.AST.Declarations.ChainId (ChainId)+import Language.PureScript.Types+import Language.PureScript.PSString (PSString)+import Language.PureScript.Label (Label)+import Language.PureScript.Names+import Language.PureScript.Roles+import Language.PureScript.TypeClassDictionaries+import Language.PureScript.Comments+import Language.PureScript.Environment+import qualified Language.PureScript.Constants.Prim as C++-- | A map of locally-bound names in scope.+type Context = [(Ident, SourceType)]++-- | Holds the data necessary to do type directed search for typed holes+data TypeSearch+ = TSBefore Environment+ -- ^ An Environment captured for later consumption by type directed search+ | TSAfter+ { tsAfterIdentifiers :: [(Qualified Text, SourceType)]+ -- ^ The identifiers that fully satisfy the subsumption check+ , tsAfterRecordFields :: Maybe [(Label, SourceType)]+ -- ^ Record fields that are available on the first argument to the typed+ -- hole+ }+ -- ^ Results of applying type directed search to the previously captured+ -- Environment+ deriving Show++onTypeSearchTypes :: (SourceType -> SourceType) -> TypeSearch -> TypeSearch+onTypeSearchTypes f = runIdentity . onTypeSearchTypesM (Identity . f)++onTypeSearchTypesM :: (Applicative m) => (SourceType -> m SourceType) -> TypeSearch -> m TypeSearch+onTypeSearchTypesM f (TSAfter i r) = TSAfter <$> traverse (traverse f) i <*> traverse (traverse (traverse f)) r+onTypeSearchTypesM _ (TSBefore env) = pure (TSBefore env)++-- | Error message hints, providing more detailed information about failure.+data ErrorMessageHint+ = ErrorUnifyingTypes SourceType SourceType+ | ErrorInExpression Expr+ | ErrorInModule ModuleName+ | ErrorInInstance (Qualified (ProperName 'ClassName)) [SourceType]+ | ErrorInSubsumption SourceType SourceType+ | ErrorCheckingAccessor Expr PSString+ | ErrorCheckingType Expr SourceType+ | ErrorCheckingKind SourceType SourceType+ | ErrorCheckingGuard+ | ErrorInferringType Expr+ | ErrorInferringKind SourceType+ | ErrorInApplication Expr SourceType Expr+ | ErrorInDataConstructor (ProperName 'ConstructorName)+ | ErrorInTypeConstructor (ProperName 'TypeName)+ | ErrorInBindingGroup (NEL.NonEmpty Ident)+ | ErrorInDataBindingGroup [ProperName 'TypeName]+ | ErrorInTypeSynonym (ProperName 'TypeName)+ | ErrorInValueDeclaration Ident+ | ErrorInTypeDeclaration Ident+ | ErrorInTypeClassDeclaration (ProperName 'ClassName)+ | ErrorInKindDeclaration (ProperName 'TypeName)+ | ErrorInRoleDeclaration (ProperName 'TypeName)+ | ErrorInForeignImport Ident+ | ErrorSolvingConstraint SourceConstraint+ | MissingConstructorImportForCoercible (Qualified (ProperName 'ConstructorName))+ | PositionedError (NEL.NonEmpty SourceSpan)+ deriving (Show)++-- | Categories of hints+data HintCategory+ = ExprHint+ | KindHint+ | CheckHint+ | PositionHint+ | SolverHint+ | OtherHint+ deriving (Show, Eq)++-- |+-- A module declaration, consisting of comments about the module, a module name,+-- a list of declarations, and a list of the declarations that are+-- explicitly exported. If the export list is Nothing, everything is exported.+--+data Module = Module SourceSpan [Comment] ModuleName [Declaration] (Maybe [DeclarationRef])+ deriving (Show)++-- | Return a module's name.+getModuleName :: Module -> ModuleName+getModuleName (Module _ _ name _ _) = name++-- | Return a module's source span.+getModuleSourceSpan :: Module -> SourceSpan+getModuleSourceSpan (Module ss _ _ _ _) = ss++-- | Return a module's declarations.+getModuleDeclarations :: Module -> [Declaration]+getModuleDeclarations (Module _ _ _ declarations _) = declarations++-- |+-- Add an import declaration for a module if it does not already explicitly import it.+--+-- Will not import an unqualified module if that module has already been imported qualified.+-- (See #2197)+--+addDefaultImport :: Qualified ModuleName -> Module -> Module+addDefaultImport (Qualified toImportAs toImport) m@(Module ss coms mn decls exps) =+ if isExistingImport `any` decls || mn == toImport then m+ else Module ss coms mn (ImportDeclaration (ss, []) toImport Implicit toImportAs : decls) exps+ where+ isExistingImport (ImportDeclaration _ mn' _ as')+ | mn' == toImport =+ case toImportAs of+ Nothing -> True+ _ -> as' == toImportAs+ isExistingImport _ = False++-- | Adds import declarations to a module for an implicit Prim import and Prim+-- | qualified as Prim, as necessary.+importPrim :: Module -> Module+importPrim =+ let+ primModName = C.Prim+ in+ addDefaultImport (Qualified (Just primModName) primModName)+ . addDefaultImport (Qualified Nothing primModName)++-- |+-- An item in a list of explicit imports or exports+--+data DeclarationRef+ -- |+ -- A type class+ --+ = TypeClassRef SourceSpan (ProperName 'ClassName)+ -- |+ -- A type operator+ --+ | TypeOpRef SourceSpan (OpName 'TypeOpName)+ -- |+ -- A type constructor with data constructors+ --+ | TypeRef SourceSpan (ProperName 'TypeName) (Maybe [ProperName 'ConstructorName])+ -- |+ -- A value+ --+ | ValueRef SourceSpan Ident+ -- |+ -- A value-level operator+ --+ | ValueOpRef SourceSpan (OpName 'ValueOpName)+ -- |+ -- A type class instance, created during typeclass desugaring (name, class name, instance types)+ --+ | TypeInstanceRef SourceSpan Ident+ -- |+ -- A module, in its entirety+ --+ | ModuleRef SourceSpan ModuleName+ -- |+ -- A value re-exported from another module. These will be inserted during+ -- elaboration in name desugaring.+ --+ | ReExportRef SourceSpan ExportSource DeclarationRef+ deriving (Show, Generic, NFData, Serialise)++instance Eq DeclarationRef where+ (TypeClassRef _ name) == (TypeClassRef _ name') = name == name'+ (TypeOpRef _ name) == (TypeOpRef _ name') = name == name'+ (TypeRef _ name dctors) == (TypeRef _ name' dctors') = name == name' && dctors == dctors'+ (ValueRef _ name) == (ValueRef _ name') = name == name'+ (ValueOpRef _ name) == (ValueOpRef _ name') = name == name'+ (TypeInstanceRef _ name) == (TypeInstanceRef _ name') = name == name'+ (ModuleRef _ name) == (ModuleRef _ name') = name == name'+ (ReExportRef _ mn ref) == (ReExportRef _ mn' ref') = mn == mn' && ref == ref'+ _ == _ = False++instance Ord DeclarationRef where+ TypeClassRef _ name `compare` TypeClassRef _ name' = compare name name'+ TypeOpRef _ name `compare` TypeOpRef _ name' = compare name name'+ TypeRef _ name dctors `compare` TypeRef _ name' dctors' = compare name name' <> compare dctors dctors'+ ValueRef _ name `compare` ValueRef _ name' = compare name name'+ ValueOpRef _ name `compare` ValueOpRef _ name' = compare name name'+ TypeInstanceRef _ name `compare` TypeInstanceRef _ name' = compare name name'+ ModuleRef _ name `compare` ModuleRef _ name' = compare name name'+ ReExportRef _ mn ref `compare` ReExportRef _ mn' ref' = compare mn mn' <> compare ref ref'+ compare ref ref' =+ compare (orderOf ref) (orderOf ref')+ where+ orderOf :: DeclarationRef -> Int+ orderOf TypeClassRef{} = 0+ orderOf TypeOpRef{} = 1+ orderOf TypeRef{} = 2+ orderOf ValueRef{} = 3+ orderOf ValueOpRef{} = 4+ orderOf TypeInstanceRef{} = 5+ orderOf ModuleRef{} = 6+ orderOf ReExportRef{} = 7++data ExportSource =+ ExportSource+ { exportSourceImportedFrom :: Maybe ModuleName+ , exportSourceDefinedIn :: ModuleName+ }+ deriving (Eq, Ord, Show, Generic, NFData, Serialise)++declRefSourceSpan :: DeclarationRef -> SourceSpan+declRefSourceSpan (TypeRef ss _ _) = ss+declRefSourceSpan (TypeOpRef ss _) = ss+declRefSourceSpan (ValueRef ss _) = ss+declRefSourceSpan (ValueOpRef ss _) = ss+declRefSourceSpan (TypeClassRef ss _) = ss+declRefSourceSpan (TypeInstanceRef ss _) = ss+declRefSourceSpan (ModuleRef ss _) = ss+declRefSourceSpan (ReExportRef ss _ _) = ss++declRefName :: DeclarationRef -> Name+declRefName (TypeRef _ n _) = TyName n+declRefName (TypeOpRef _ n) = TyOpName n+declRefName (ValueRef _ n) = IdentName n+declRefName (ValueOpRef _ n) = ValOpName n+declRefName (TypeClassRef _ n) = TyClassName n+declRefName (TypeInstanceRef _ n) = IdentName n+declRefName (ModuleRef _ n) = ModName n+declRefName (ReExportRef _ _ ref) = declRefName ref++getTypeRef :: DeclarationRef -> Maybe (ProperName 'TypeName, Maybe [ProperName 'ConstructorName])+getTypeRef (TypeRef _ name dctors) = Just (name, dctors)+getTypeRef _ = Nothing++getTypeOpRef :: DeclarationRef -> Maybe (OpName 'TypeOpName)+getTypeOpRef (TypeOpRef _ op) = Just op+getTypeOpRef _ = Nothing++getValueRef :: DeclarationRef -> Maybe Ident+getValueRef (ValueRef _ name) = Just name+getValueRef _ = Nothing++getValueOpRef :: DeclarationRef -> Maybe (OpName 'ValueOpName)+getValueOpRef (ValueOpRef _ op) = Just op+getValueOpRef _ = Nothing++getTypeClassRef :: DeclarationRef -> Maybe (ProperName 'ClassName)+getTypeClassRef (TypeClassRef _ name) = Just name+getTypeClassRef _ = Nothing++isModuleRef :: DeclarationRef -> Bool+isModuleRef ModuleRef{} = True+isModuleRef _ = False++-- |+-- The data type which specifies type of import declaration+--+data ImportDeclarationType+ -- |+ -- An import with no explicit list: `import M`.+ --+ = Implicit+ -- |+ -- An import with an explicit list of references to import: `import M (foo)`+ --+ | Explicit [DeclarationRef]+ -- |+ -- An import with a list of references to hide: `import M hiding (foo)`+ --+ | Hiding [DeclarationRef]+ deriving (Eq, Show, Generic, Serialise)++isImplicit :: ImportDeclarationType -> Bool+isImplicit Implicit = True+isImplicit _ = False++isExplicit :: ImportDeclarationType -> Bool+isExplicit (Explicit _) = True+isExplicit _ = False++-- | A role declaration assigns a list of roles to a type constructor's+-- parameters, e.g.:+--+-- @type role T representational phantom@+--+-- In this example, @T@ is the identifier and @[representational, phantom]@ is+-- the list of roles (@T@ presumably having two parameters).+data RoleDeclarationData = RoleDeclarationData+ { rdeclSourceAnn :: !SourceAnn+ , rdeclIdent :: !(ProperName 'TypeName)+ , rdeclRoles :: ![Role]+ } deriving (Show, Eq)++-- | A type declaration assigns a type to an identifier, eg:+--+-- @identity :: forall a. a -> a@+--+-- In this example @identity@ is the identifier and @forall a. a -> a@ the type.+data TypeDeclarationData = TypeDeclarationData+ { tydeclSourceAnn :: !SourceAnn+ , tydeclIdent :: !Ident+ , tydeclType :: !SourceType+ } deriving (Show, Eq)++overTypeDeclaration :: (TypeDeclarationData -> TypeDeclarationData) -> Declaration -> Declaration+overTypeDeclaration f d = maybe d (TypeDeclaration . f) (getTypeDeclaration d)++getTypeDeclaration :: Declaration -> Maybe TypeDeclarationData+getTypeDeclaration (TypeDeclaration d) = Just d+getTypeDeclaration _ = Nothing++unwrapTypeDeclaration :: TypeDeclarationData -> (Ident, SourceType)+unwrapTypeDeclaration td = (tydeclIdent td, tydeclType td)++-- | A value declaration assigns a name and potential binders, to an expression (or multiple guarded expressions).+--+-- @double x = x + x@+--+-- In this example @double@ is the identifier, @x@ is a binder and @x + x@ is the expression.+data ValueDeclarationData a = ValueDeclarationData+ { valdeclSourceAnn :: !SourceAnn+ , valdeclIdent :: !Ident+ -- ^ The declared value's name+ , valdeclName :: !NameKind+ -- ^ Whether or not this value is exported/visible+ , valdeclBinders :: ![Binder]+ , valdeclExpression :: !a+ } deriving (Show, Functor, Foldable, Traversable)++overValueDeclaration :: (ValueDeclarationData [GuardedExpr] -> ValueDeclarationData [GuardedExpr]) -> Declaration -> Declaration+overValueDeclaration f d = maybe d (ValueDeclaration . f) (getValueDeclaration d)++getValueDeclaration :: Declaration -> Maybe (ValueDeclarationData [GuardedExpr])+getValueDeclaration (ValueDeclaration d) = Just d+getValueDeclaration _ = Nothing++pattern ValueDecl :: SourceAnn -> Ident -> NameKind -> [Binder] -> [GuardedExpr] -> Declaration+pattern ValueDecl sann ident name binders expr+ = ValueDeclaration (ValueDeclarationData sann ident name binders expr)++data DataConstructorDeclaration = DataConstructorDeclaration+ { dataCtorAnn :: !SourceAnn+ , dataCtorName :: !(ProperName 'ConstructorName)+ , dataCtorFields :: ![(Ident, SourceType)]+ } deriving (Show, Eq)++mapDataCtorFields :: ([(Ident, SourceType)] -> [(Ident, SourceType)]) -> DataConstructorDeclaration -> DataConstructorDeclaration+mapDataCtorFields f DataConstructorDeclaration{..} = DataConstructorDeclaration { dataCtorFields = f dataCtorFields, .. }++traverseDataCtorFields :: Monad m => ([(Ident, SourceType)] -> m [(Ident, SourceType)]) -> DataConstructorDeclaration -> m DataConstructorDeclaration+traverseDataCtorFields f DataConstructorDeclaration{..} = DataConstructorDeclaration dataCtorAnn dataCtorName <$> f dataCtorFields++-- |+-- The data type of declarations+--+data Declaration+ -- |+ -- A data type declaration (data or newtype, name, arguments, data constructors)+ --+ = DataDeclaration SourceAnn DataDeclType (ProperName 'TypeName) [(Text, Maybe SourceType)] [DataConstructorDeclaration]+ -- |+ -- A minimal mutually recursive set of data type declarations+ --+ | DataBindingGroupDeclaration (NEL.NonEmpty Declaration)+ -- |+ -- A type synonym declaration (name, arguments, type)+ --+ | TypeSynonymDeclaration SourceAnn (ProperName 'TypeName) [(Text, Maybe SourceType)] SourceType+ -- |+ -- A kind signature declaration+ --+ | KindDeclaration SourceAnn KindSignatureFor (ProperName 'TypeName) SourceType+ -- |+ -- A role declaration (name, roles)+ --+ | RoleDeclaration {-# UNPACK #-} !RoleDeclarationData+ -- |+ -- A type declaration for a value (name, ty)+ --+ | TypeDeclaration {-# UNPACK #-} !TypeDeclarationData+ -- |+ -- A value declaration (name, top-level binders, optional guard, value)+ --+ | ValueDeclaration {-# UNPACK #-} !(ValueDeclarationData [GuardedExpr])+ -- |+ -- A declaration paired with pattern matching in let-in expression (binder, optional guard, value)+ | BoundValueDeclaration SourceAnn Binder Expr+ -- |+ -- A minimal mutually recursive set of value declarations+ --+ | BindingGroupDeclaration (NEL.NonEmpty ((SourceAnn, Ident), NameKind, Expr))+ -- |+ -- A foreign import declaration (name, type)+ --+ | ExternDeclaration SourceAnn Ident SourceType+ -- |+ -- A data type foreign import (name, kind)+ --+ | ExternDataDeclaration SourceAnn (ProperName 'TypeName) SourceType+ -- |+ -- A fixity declaration+ --+ | FixityDeclaration SourceAnn (Either ValueFixity TypeFixity)+ -- |+ -- A module import (module name, qualified/unqualified/hiding, optional "qualified as" name)+ --+ | ImportDeclaration SourceAnn ModuleName ImportDeclarationType (Maybe ModuleName)+ -- |+ -- A type class declaration (name, argument, implies, member declarations)+ --+ | TypeClassDeclaration SourceAnn (ProperName 'ClassName) [(Text, Maybe SourceType)] [SourceConstraint] [FunctionalDependency] [Declaration]+ -- |+ -- A type instance declaration (instance chain, chain index, name,+ -- dependencies, class name, instance types, member declarations)+ --+ | TypeInstanceDeclaration SourceAnn ChainId Integer (Either Text Ident) [SourceConstraint] (Qualified (ProperName 'ClassName)) [SourceType] TypeInstanceBody+ deriving (Show)++data ValueFixity = ValueFixity Fixity (Qualified (Either Ident (ProperName 'ConstructorName))) (OpName 'ValueOpName)+ deriving (Eq, Ord, Show)++data TypeFixity = TypeFixity Fixity (Qualified (ProperName 'TypeName)) (OpName 'TypeOpName)+ deriving (Eq, Ord, Show)++pattern ValueFixityDeclaration :: SourceAnn -> Fixity -> Qualified (Either Ident (ProperName 'ConstructorName)) -> OpName 'ValueOpName -> Declaration+pattern ValueFixityDeclaration sa fixity name op = FixityDeclaration sa (Left (ValueFixity fixity name op))++pattern TypeFixityDeclaration :: SourceAnn -> Fixity -> Qualified (ProperName 'TypeName) -> OpName 'TypeOpName -> Declaration+pattern TypeFixityDeclaration sa fixity name op = FixityDeclaration sa (Right (TypeFixity fixity name op))++-- | The members of a type class instance declaration+data TypeInstanceBody+ = DerivedInstance+ -- ^ This is a derived instance+ | NewtypeInstance+ -- ^ This is an instance derived from a newtype+ | NewtypeInstanceWithDictionary Expr+ -- ^ This is an instance derived from a newtype, desugared to include a+ -- dictionary for the type under the newtype.+ | ExplicitInstance [Declaration]+ -- ^ This is a regular (explicit) instance+ deriving (Show)++mapTypeInstanceBody :: ([Declaration] -> [Declaration]) -> TypeInstanceBody -> TypeInstanceBody+mapTypeInstanceBody f = runIdentity . traverseTypeInstanceBody (Identity . f)++-- | A traversal for TypeInstanceBody+traverseTypeInstanceBody :: (Applicative f) => ([Declaration] -> f [Declaration]) -> TypeInstanceBody -> f TypeInstanceBody+traverseTypeInstanceBody f (ExplicitInstance ds) = ExplicitInstance <$> f ds+traverseTypeInstanceBody _ other = pure other++-- | What sort of declaration the kind signature applies to.+data KindSignatureFor+ = DataSig+ | NewtypeSig+ | TypeSynonymSig+ | ClassSig+ deriving (Eq, Ord, Show)++declSourceAnn :: Declaration -> SourceAnn+declSourceAnn (DataDeclaration sa _ _ _ _) = sa+declSourceAnn (DataBindingGroupDeclaration ds) = declSourceAnn (NEL.head ds)+declSourceAnn (TypeSynonymDeclaration sa _ _ _) = sa+declSourceAnn (KindDeclaration sa _ _ _) = sa+declSourceAnn (RoleDeclaration rd) = rdeclSourceAnn rd+declSourceAnn (TypeDeclaration td) = tydeclSourceAnn td+declSourceAnn (ValueDeclaration vd) = valdeclSourceAnn vd+declSourceAnn (BoundValueDeclaration sa _ _) = sa+declSourceAnn (BindingGroupDeclaration ds) = let ((sa, _), _, _) = NEL.head ds in sa+declSourceAnn (ExternDeclaration sa _ _) = sa+declSourceAnn (ExternDataDeclaration sa _ _) = sa+declSourceAnn (FixityDeclaration sa _) = sa+declSourceAnn (ImportDeclaration sa _ _ _) = sa+declSourceAnn (TypeClassDeclaration sa _ _ _ _ _) = sa+declSourceAnn (TypeInstanceDeclaration sa _ _ _ _ _ _ _) = sa++declSourceSpan :: Declaration -> SourceSpan+declSourceSpan = fst . declSourceAnn++declName :: Declaration -> Maybe Name+declName (DataDeclaration _ _ n _ _) = Just (TyName n)+declName (TypeSynonymDeclaration _ n _ _) = Just (TyName n)+declName (ValueDeclaration vd) = Just (IdentName (valdeclIdent vd))+declName (ExternDeclaration _ n _) = Just (IdentName n)+declName (ExternDataDeclaration _ n _) = Just (TyName n)+declName (FixityDeclaration _ (Left (ValueFixity _ _ n))) = Just (ValOpName n)+declName (FixityDeclaration _ (Right (TypeFixity _ _ n))) = Just (TyOpName n)+declName (TypeClassDeclaration _ n _ _ _ _) = Just (TyClassName n)+declName (TypeInstanceDeclaration _ _ _ n _ _ _ _) = IdentName <$> hush n+declName ImportDeclaration{} = Nothing+declName BindingGroupDeclaration{} = Nothing+declName DataBindingGroupDeclaration{} = Nothing+declName BoundValueDeclaration{} = Nothing+declName KindDeclaration{} = Nothing+declName TypeDeclaration{} = Nothing+declName RoleDeclaration{} = Nothing++-- |+-- Test if a declaration is a value declaration+--+isValueDecl :: Declaration -> Bool+isValueDecl ValueDeclaration{} = True+isValueDecl _ = False++-- |+-- Test if a declaration is a data type declaration+--+isDataDecl :: Declaration -> Bool+isDataDecl DataDeclaration{} = True+isDataDecl _ = False++-- |+-- Test if a declaration is a type synonym declaration+--+isTypeSynonymDecl :: Declaration -> Bool+isTypeSynonymDecl TypeSynonymDeclaration{} = True+isTypeSynonymDecl _ = False++-- |+-- Test if a declaration is a module import+--+isImportDecl :: Declaration -> Bool+isImportDecl ImportDeclaration{} = True+isImportDecl _ = False++-- |+-- Test if a declaration is a role declaration+--+isRoleDecl :: Declaration -> Bool+isRoleDecl RoleDeclaration{} = True+isRoleDecl _ = False++-- |+-- Test if a declaration is a data type foreign import+--+isExternDataDecl :: Declaration -> Bool+isExternDataDecl ExternDataDeclaration{} = True+isExternDataDecl _ = False++-- |+-- Test if a declaration is a fixity declaration+--+isFixityDecl :: Declaration -> Bool+isFixityDecl FixityDeclaration{} = True+isFixityDecl _ = False++getFixityDecl :: Declaration -> Maybe (Either ValueFixity TypeFixity)+getFixityDecl (FixityDeclaration _ fixity) = Just fixity+getFixityDecl _ = Nothing++-- |+-- Test if a declaration is a foreign import+--+isExternDecl :: Declaration -> Bool+isExternDecl ExternDeclaration{} = True+isExternDecl _ = False++-- |+-- Test if a declaration is a type class instance declaration+--+isTypeClassInstanceDecl :: Declaration -> Bool+isTypeClassInstanceDecl TypeInstanceDeclaration{} = True+isTypeClassInstanceDecl _ = False++-- |+-- Test if a declaration is a type class declaration+--+isTypeClassDecl :: Declaration -> Bool+isTypeClassDecl TypeClassDeclaration{} = True+isTypeClassDecl _ = False++-- |+-- Test if a declaration is a kind signature declaration.+--+isKindDecl :: Declaration -> Bool+isKindDecl KindDeclaration{} = True+isKindDecl _ = False++-- |+-- Recursively flatten data binding groups in the list of declarations+flattenDecls :: [Declaration] -> [Declaration]+flattenDecls = concatMap flattenOne+ where flattenOne :: Declaration -> [Declaration]+ flattenOne (DataBindingGroupDeclaration decls) = concatMap flattenOne decls+ flattenOne d = [d]++-- |+-- A guard is just a boolean-valued expression that appears alongside a set of binders+--+data Guard = ConditionGuard Expr+ | PatternGuard Binder Expr+ deriving (Show)++-- |+-- The right hand side of a binder in value declarations+-- and case expressions.+data GuardedExpr = GuardedExpr [Guard] Expr+ deriving (Show)++pattern MkUnguarded :: Expr -> GuardedExpr+pattern MkUnguarded e = GuardedExpr [] e++-- |+-- Data type for expressions and terms+--+data Expr+ -- |+ -- A literal value+ --+ = Literal SourceSpan (Literal Expr)+ -- |+ -- A prefix -, will be desugared+ --+ | UnaryMinus SourceSpan Expr+ -- |+ -- Binary operator application. During the rebracketing phase of desugaring, this data constructor+ -- will be removed.+ --+ | BinaryNoParens Expr Expr Expr+ -- |+ -- Explicit parentheses. During the rebracketing phase of desugaring, this data constructor+ -- will be removed.+ --+ -- Note: although it seems this constructor is not used, it _is_ useful, since it prevents+ -- certain traversals from matching.+ --+ | Parens Expr+ -- |+ -- An record property accessor expression (e.g. `obj.x` or `_.x`).+ -- Anonymous arguments will be removed during desugaring and expanded+ -- into a lambda that reads a property from a record.+ --+ | Accessor PSString Expr+ -- |+ -- Partial record update+ --+ | ObjectUpdate Expr [(PSString, Expr)]+ -- |+ -- Object updates with nested support: `x { foo { bar = e } }`+ -- Replaced during desugaring into a `Let` and nested `ObjectUpdate`s+ --+ | ObjectUpdateNested Expr (PathTree Expr)+ -- |+ -- Function introduction+ --+ | Abs Binder Expr+ -- |+ -- Function application+ --+ | App Expr Expr+ -- |+ -- Hint that an expression is unused.+ -- This is used to ignore type class dictionaries that are necessarily empty.+ -- The inner expression lets us solve subgoals before eliminating the whole expression.+ -- The code gen will render this as `undefined`, regardless of what the inner expression is.+ | Unused Expr+ -- |+ -- Variable+ --+ | Var SourceSpan (Qualified Ident)+ -- |+ -- An operator. This will be desugared into a function during the "operators"+ -- phase of desugaring.+ --+ | Op SourceSpan (Qualified (OpName 'ValueOpName))+ -- |+ -- Conditional (if-then-else expression)+ --+ | IfThenElse Expr Expr Expr+ -- |+ -- A data constructor+ --+ | Constructor SourceSpan (Qualified (ProperName 'ConstructorName))+ -- |+ -- A case expression. During the case expansion phase of desugaring, top-level binders will get+ -- desugared into case expressions, hence the need for guards and multiple binders per branch here.+ --+ | Case [Expr] [CaseAlternative]+ -- |+ -- A value with a type annotation+ --+ | TypedValue Bool Expr SourceType+ -- |+ -- A let binding+ --+ | Let WhereProvenance [Declaration] Expr+ -- |+ -- A do-notation block+ --+ | Do (Maybe ModuleName) [DoNotationElement]+ -- |+ -- An ado-notation block+ --+ | Ado (Maybe ModuleName) [DoNotationElement] Expr+ -- |+ -- An application of a typeclass dictionary constructor. The value should be+ -- an ObjectLiteral.+ --+ | TypeClassDictionaryConstructorApp (Qualified (ProperName 'ClassName)) Expr+ -- |+ -- A placeholder for a type class dictionary to be inserted later. At the end of type checking, these+ -- placeholders will be replaced with actual expressions representing type classes dictionaries which+ -- can be evaluated at runtime. The constructor arguments represent (in order): whether or not to look+ -- at superclass implementations when searching for a dictionary, the type class name and+ -- instance type, and the type class dictionaries in scope.+ --+ | TypeClassDictionary SourceConstraint+ (M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) (NEL.NonEmpty NamedDict))))+ [ErrorMessageHint]+ -- |+ -- A typeclass dictionary accessor, the implementation is left unspecified until CoreFn desugaring.+ --+ | TypeClassDictionaryAccessor (Qualified (ProperName 'ClassName)) Ident+ -- |+ -- A placeholder for a superclass dictionary to be turned into a TypeClassDictionary during typechecking+ --+ | DeferredDictionary (Qualified (ProperName 'ClassName)) [SourceType]+ -- |+ -- A placeholder for an anonymous function argument+ --+ | AnonymousArgument+ -- |+ -- A typed hole that will be turned into a hint/error during typechecking+ --+ | Hole Text+ -- |+ -- A value with source position information+ --+ | PositionedValue SourceSpan [Comment] Expr+ deriving (Show)++-- |+-- Metadata that tells where a let binding originated+--+data WhereProvenance+ -- |+ -- The let binding was originally a where clause+ --+ = FromWhere+ -- |+ -- The let binding was always a let binding+ --+ | FromLet+ deriving (Show)++-- |+-- An alternative in a case statement+--+data CaseAlternative = CaseAlternative+ { -- |+ -- A collection of binders with which to match the inputs+ --+ caseAlternativeBinders :: [Binder]+ -- |+ -- The result expression or a collect of guarded expressions+ --+ , caseAlternativeResult :: [GuardedExpr]+ } deriving (Show)++-- |+-- A statement in a do-notation block+--+data DoNotationElement+ -- |+ -- A monadic value without a binder+ --+ = DoNotationValue Expr+ -- |+ -- A monadic value with a binder+ --+ | DoNotationBind Binder Expr+ -- |+ -- A let statement, i.e. a pure value with a binder+ --+ | DoNotationLet [Declaration]+ -- |+ -- A do notation element with source position information+ --+ | PositionedDoNotationElement SourceSpan [Comment] DoNotationElement+ deriving (Show)+++-- For a record update such as:+--+-- x { foo = 0+-- , bar { baz = 1+-- , qux = 2 } }+--+-- We represent the updates as the `PathTree`:+--+-- [ ("foo", Leaf 3)+-- , ("bar", Branch [ ("baz", Leaf 1)+-- , ("qux", Leaf 2) ]) ]+--+-- Which we then convert to an expression representing the following:+--+-- let x' = x+-- in x' { foo = 0+-- , bar = x'.bar { baz = 1+-- , qux = 2 } }+--+-- The `let` here is required to prevent re-evaluating the object expression `x`.+-- However we don't generate this when using an anonymous argument for the object.+--++newtype PathTree t = PathTree (AssocList PSString (PathNode t))+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable)++data PathNode t = Leaf t | Branch (PathTree t)+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable)++newtype AssocList k t = AssocList { runAssocList :: [(k, t)] }+ deriving (Show, Eq, Ord, Foldable, Functor, Traversable)++$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''DeclarationRef)+$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ImportDeclarationType)+$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ExportSource)++isTrueExpr :: Expr -> Bool+isTrueExpr (Literal _ (BooleanLiteral True)) = True+isTrueExpr (Var _ (Qualified (Just (ModuleName "Prelude")) (Ident "otherwise"))) = True+isTrueExpr (Var _ (Qualified (Just (ModuleName "Data.Boolean")) (Ident "otherwise"))) = True+isTrueExpr (TypedValue _ e _) = isTrueExpr e+isTrueExpr (PositionedValue _ _ e) = isTrueExpr e+isTrueExpr _ = False
+ src/Language/PureScript/AST/Declarations/ChainId.hs view
@@ -0,0 +1,20 @@+module Language.PureScript.AST.Declarations.ChainId+ ( ChainId+ , mkChainId+ ) where++import Prelude+import qualified Language.PureScript.AST.SourcePos as Pos+import Control.DeepSeq (NFData)+import Codec.Serialise (Serialise)++-- |+-- For a given instance chain, stores the chain's file name and+-- the starting source pos of the first instance in the chain.+-- This data is used to determine which instances are part of+-- the same instance chain.+newtype ChainId = ChainId (String, Pos.SourcePos)+ deriving (Eq, Ord, Show, NFData, Serialise)++mkChainId :: String -> Pos.SourcePos -> ChainId+mkChainId fileName startingSourcePos = ChainId (fileName, startingSourcePos)
+ src/Language/PureScript/AST/Exported.hs view
@@ -0,0 +1,156 @@+module Language.PureScript.AST.Exported+ ( exportedDeclarations+ , isExported+ ) where++import Prelude.Compat+import Protolude (sortOn)++import Control.Category ((>>>))++import Data.Maybe (mapMaybe)+import qualified Data.Map as M++import Language.PureScript.AST.Declarations+import Language.PureScript.Types+import Language.PureScript.Names++-- |+-- Return a list of all declarations which are exported from a module.+-- This function descends into data declarations to filter out unexported+-- data constructors, and also filters out type instance declarations if+-- they refer to classes or types which are not themselves exported.+--+-- Note that this function assumes that the module has already had its imports+-- desugared using 'Language.PureScript.Sugar.Names.desugarImports'. It will+-- produce incorrect results if this is not the case - for example, type class+-- instances will be incorrectly removed in some cases.+--+-- The returned declarations are in the same order as they appear in the export+-- list, unless there is no export list, in which case they appear in the same+-- order as they do in the source file.+--+exportedDeclarations :: Module -> [Declaration]+exportedDeclarations (Module _ _ mn decls exps) = go decls+ where+ go = flattenDecls+ >>> filter (isExported exps)+ >>> map (filterDataConstructors exps)+ >>> filterInstances mn exps+ >>> maybe id reorder exps++-- |+-- Filter out all data constructors from a declaration which are not exported.+-- If the supplied declaration is not a data declaration, this function returns+-- it unchanged.+--+filterDataConstructors :: Maybe [DeclarationRef] -> Declaration -> Declaration+filterDataConstructors exps (DataDeclaration sa dType tyName tyArgs dctors) =+ DataDeclaration sa dType tyName tyArgs $+ filter (isDctorExported tyName exps . dataCtorName) dctors+filterDataConstructors _ other = other++-- |+-- Filter out all the type instances from a list of declarations which+-- reference a type or type class which is both local and not exported.+--+-- Note that this function assumes that the module has already had its imports+-- desugared using "Language.PureScript.Sugar.Names.desugarImports". It will+-- produce incorrect results if this is not the case - for example, type class+-- instances will be incorrectly removed in some cases.+--+filterInstances+ :: ModuleName+ -> Maybe [DeclarationRef]+ -> [Declaration]+ -> [Declaration]+filterInstances _ Nothing = id+filterInstances mn (Just exps) =+ let refs = Left `map` mapMaybe typeClassName exps+ ++ Right `map` mapMaybe typeName exps+ in filter (all (visibleOutside refs) . typeInstanceConstituents)+ where+ -- Given a Qualified ProperName, and a list of all exported types and type+ -- classes, returns whether the supplied Qualified ProperName is visible+ -- outside this module. This is true if one of the following hold:+ --+ -- * the name is defined in the same module and is exported,+ -- * the name is defined in a different module (and must be exported from+ -- that module; the code would fail to compile otherwise).+ visibleOutside+ :: [Either (ProperName 'ClassName) (ProperName 'TypeName)]+ -> Either (Qualified (ProperName 'ClassName)) (Qualified (ProperName 'TypeName))+ -> Bool+ visibleOutside refs q+ | either checkQual checkQual q = True+ | otherwise = either (Left . disqualify) (Right . disqualify) q `elem` refs++ -- Check that a qualified name is qualified for a different module+ checkQual :: Qualified a -> Bool+ checkQual q = isQualified q && not (isQualifiedWith mn q)++ typeName :: DeclarationRef -> Maybe (ProperName 'TypeName)+ typeName (TypeRef _ n _) = Just n+ typeName _ = Nothing++ typeClassName :: DeclarationRef -> Maybe (ProperName 'ClassName)+ typeClassName (TypeClassRef _ n) = Just n+ typeClassName _ = Nothing++-- |+-- Get all type and type class names referenced by a type instance declaration.+--+typeInstanceConstituents :: Declaration -> [Either (Qualified (ProperName 'ClassName)) (Qualified (ProperName 'TypeName))]+typeInstanceConstituents (TypeInstanceDeclaration _ _ _ _ constraints className tys _) =+ Left className : (concatMap fromConstraint constraints ++ concatMap fromType tys)+ where++ fromConstraint c = Left (constraintClass c) : concatMap fromType (constraintArgs c)+ fromType = everythingOnTypes (++) go++ -- Note that type synonyms are disallowed in instance declarations, so+ -- we don't need to handle them here.+ go (TypeConstructor _ n) = [Right n]+ go (ConstrainedType _ c _) = fromConstraint c+ go _ = []++typeInstanceConstituents _ = []+++-- |+-- Test if a declaration is exported, given a module's export list. Note that+-- this function does not account for type instance declarations of+-- non-exported types, or non-exported data constructors. Therefore, you should+-- prefer 'exportedDeclarations' to this function, where possible.+--+isExported :: Maybe [DeclarationRef] -> Declaration -> Bool+isExported Nothing _ = True+isExported _ TypeInstanceDeclaration{} = True+isExported (Just exps) decl = any matches exps+ where+ matches declRef = declName decl == Just (declRefName declRef)++-- |+-- Test if a data constructor for a given type is exported, given a module's+-- export list. Prefer 'exportedDeclarations' to this function, where possible.+--+isDctorExported :: ProperName 'TypeName -> Maybe [DeclarationRef] -> ProperName 'ConstructorName -> Bool+isDctorExported _ Nothing _ = True+isDctorExported ident (Just exps) ctor = test `any` exps+ where+ test (TypeRef _ ident' Nothing) = ident == ident'+ test (TypeRef _ ident' (Just ctors)) = ident == ident' && ctor `elem` ctors+ test _ = False++-- |+-- Reorder declarations based on the order they appear in the given export+-- list.+--+reorder :: [DeclarationRef] -> [Declaration] -> [Declaration]+reorder refs =+ sortOn refIndex+ where+ refIndices =+ M.fromList $ zip (map declRefName refs) [(0::Int)..]+ refIndex decl =+ declName decl >>= flip M.lookup refIndices
+ src/Language/PureScript/AST/Literals.hs view
@@ -0,0 +1,38 @@+-- |+-- The core functional representation for literal values.+--+module Language.PureScript.AST.Literals where++import Prelude.Compat+import Language.PureScript.PSString (PSString)++-- |+-- Data type for literal values. Parameterised so it can be used for Exprs and+-- Binders.+--+data Literal a+ -- |+ -- A numeric literal+ --+ = NumericLiteral (Either Integer Double)+ -- |+ -- A string literal+ --+ | StringLiteral PSString+ -- |+ -- A character literal+ --+ | CharLiteral Char+ -- |+ -- A boolean literal+ --+ | BooleanLiteral Bool+ -- |+ -- An array literal+ --+ | ArrayLiteral [a]+ -- |+ -- An object literal+ --+ | ObjectLiteral [(PSString, a)]+ deriving (Eq, Ord, Show, Functor)
+ src/Language/PureScript/AST/Operators.hs view
@@ -0,0 +1,60 @@+-- |+-- Operators fixity and associativity+--+module Language.PureScript.AST.Operators where++import Prelude.Compat++import Codec.Serialise (Serialise)+import GHC.Generics (Generic)+import Control.DeepSeq (NFData)+import Data.Aeson ((.=))+import qualified Data.Aeson as A++import Language.PureScript.Crash++-- |+-- A precedence level for an infix operator+--+type Precedence = Integer++-- |+-- Associativity for infix operators+--+data Associativity = Infixl | Infixr | Infix+ deriving (Show, Eq, Ord, Generic)++instance NFData Associativity+instance Serialise Associativity++showAssoc :: Associativity -> String+showAssoc Infixl = "infixl"+showAssoc Infixr = "infixr"+showAssoc Infix = "infix"++readAssoc :: String -> Associativity+readAssoc "infixl" = Infixl+readAssoc "infixr" = Infixr+readAssoc "infix" = Infix+readAssoc _ = internalError "readAssoc: no parse"++instance A.ToJSON Associativity where+ toJSON = A.toJSON . showAssoc++instance A.FromJSON Associativity where+ parseJSON = fmap readAssoc . A.parseJSON++-- |+-- Fixity data for infix operators+--+data Fixity = Fixity Associativity Precedence+ deriving (Show, Eq, Ord, Generic)++instance NFData Fixity+instance Serialise Fixity++instance A.ToJSON Fixity where+ toJSON (Fixity associativity precedence) =+ A.object [ "associativity" .= associativity+ , "precedence" .= precedence+ ]
+ src/Language/PureScript/AST/SourcePos.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE DeriveAnyClass #-}+-- |+-- Source position information+--+module Language.PureScript.AST.SourcePos where++import Prelude.Compat++import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import Data.Aeson ((.=), (.:))+import Data.Text (Text)+import GHC.Generics (Generic)+import Language.PureScript.Comments+import qualified Data.Aeson as A+import qualified Data.Text as T+import System.FilePath (makeRelative)++-- | Source annotation - position information and comments.+type SourceAnn = (SourceSpan, [Comment])++-- | Source position information+data SourcePos = SourcePos+ { sourcePosLine :: Int+ -- ^ Line number+ , sourcePosColumn :: Int+ -- ^ Column number+ } deriving (Show, Eq, Ord, Generic, NFData, Serialise)++displaySourcePos :: SourcePos -> Text+displaySourcePos sp =+ "line " <> T.pack (show (sourcePosLine sp)) <>+ ", column " <> T.pack (show (sourcePosColumn sp))++displaySourcePosShort :: SourcePos -> Text+displaySourcePosShort sp =+ T.pack (show (sourcePosLine sp)) <>+ ":" <> T.pack (show (sourcePosColumn sp))++instance A.ToJSON SourcePos where+ toJSON SourcePos{..} =+ A.toJSON [sourcePosLine, sourcePosColumn]++instance A.FromJSON SourcePos where+ parseJSON arr = do+ [line, col] <- A.parseJSON arr+ return $ SourcePos line col++data SourceSpan = SourceSpan+ { spanName :: String+ -- ^ Source name+ , spanStart :: SourcePos+ -- ^ Start of the span+ , spanEnd :: SourcePos+ -- ^ End of the span+ } deriving (Show, Eq, Ord, Generic, NFData, Serialise)++displayStartEndPos :: SourceSpan -> Text+displayStartEndPos sp =+ "(" <>+ displaySourcePos (spanStart sp) <> " - " <>+ displaySourcePos (spanEnd sp) <> ")"++displayStartEndPosShort :: SourceSpan -> Text+displayStartEndPosShort sp =+ displaySourcePosShort (spanStart sp) <> " - " <>+ displaySourcePosShort (spanEnd sp)++displaySourceSpan :: FilePath -> SourceSpan -> Text+displaySourceSpan relPath sp =+ T.pack (makeRelative relPath (spanName sp)) <> ":" <>+ displayStartEndPosShort sp <> " " <>+ displayStartEndPos sp++instance A.ToJSON SourceSpan where+ toJSON SourceSpan{..} =+ A.object [ "name" .= spanName+ , "start" .= spanStart+ , "end" .= spanEnd+ ]++instance A.FromJSON SourceSpan where+ parseJSON = A.withObject "SourceSpan" $ \o ->+ SourceSpan <$>+ o .: "name" <*>+ o .: "start" <*>+ o .: "end"++internalModuleSourceSpan :: String -> SourceSpan+internalModuleSourceSpan name = SourceSpan name (SourcePos 0 0) (SourcePos 0 0)++nullSourceSpan :: SourceSpan+nullSourceSpan = internalModuleSourceSpan ""++nullSourceAnn :: SourceAnn+nullSourceAnn = (nullSourceSpan, [])++pattern NullSourceSpan :: SourceSpan+pattern NullSourceSpan = SourceSpan "" (SourcePos 0 0) (SourcePos 0 0)++pattern NullSourceAnn :: SourceAnn+pattern NullSourceAnn = (NullSourceSpan, [])++nonEmptySpan :: SourceAnn -> Maybe SourceSpan+nonEmptySpan (NullSourceSpan, _) = Nothing+nonEmptySpan (ss, _) = Just ss++widenSourceSpan :: SourceSpan -> SourceSpan -> SourceSpan+widenSourceSpan NullSourceSpan b = b+widenSourceSpan a NullSourceSpan = a+widenSourceSpan (SourceSpan n1 s1 e1) (SourceSpan n2 s2 e2) =+ SourceSpan n (min s1 s2) (max e1 e2)+ where+ n | n1 == "" = n2+ | otherwise = n1++widenSourceAnn :: SourceAnn -> SourceAnn -> SourceAnn+widenSourceAnn (s1, _) (s2, _) = (widenSourceSpan s1 s2, [])
+ src/Language/PureScript/AST/Traversals.hs view
@@ -0,0 +1,681 @@+-- |+-- AST traversal helpers+--+module Language.PureScript.AST.Traversals where++import Prelude.Compat++import Control.Monad++import Data.Foldable (fold)+import Data.List (mapAccumL)+import Data.Maybe (mapMaybe)+import qualified Data.List.NonEmpty as NEL+import qualified Data.Map as M+import qualified Data.Set as S++import Language.PureScript.AST.Binders+import Language.PureScript.AST.Declarations+import Language.PureScript.AST.Literals+import Language.PureScript.Names+import Language.PureScript.Traversals+import Language.PureScript.TypeClassDictionaries (TypeClassDictionaryInScope(..))+import Language.PureScript.Types++guardedExprM :: Applicative m+ => (Guard -> m Guard)+ -> (Expr -> m Expr)+ -> GuardedExpr+ -> m GuardedExpr+guardedExprM f g (GuardedExpr guards rhs) =+ GuardedExpr <$> traverse f guards <*> g rhs++mapGuardedExpr :: (Guard -> Guard)+ -> (Expr -> Expr)+ -> GuardedExpr+ -> GuardedExpr+mapGuardedExpr f g (GuardedExpr guards rhs) =+ GuardedExpr (fmap f guards) (g rhs)++litM :: Monad m => (a -> m a) -> Literal a -> m (Literal a)+litM go (ObjectLiteral as) = ObjectLiteral <$> traverse (sndM go) as+litM go (ArrayLiteral as) = ArrayLiteral <$> traverse go as+litM _ other = pure other++everywhereOnValues+ :: (Declaration -> Declaration)+ -> (Expr -> Expr)+ -> (Binder -> Binder)+ -> ( Declaration -> Declaration+ , Expr -> Expr+ , Binder -> Binder+ )+everywhereOnValues f g h = (f', g', h')+ where+ f' :: Declaration -> Declaration+ f' (DataBindingGroupDeclaration ds) = f (DataBindingGroupDeclaration (fmap f' ds))+ f' (ValueDecl sa name nameKind bs val) =+ f (ValueDecl sa name nameKind (fmap h' bs) (fmap (mapGuardedExpr handleGuard g') val))+ f' (BoundValueDeclaration sa b expr) = f (BoundValueDeclaration sa (h' b) (g' expr))+ f' (BindingGroupDeclaration ds) = f (BindingGroupDeclaration (fmap (\(name, nameKind, val) -> (name, nameKind, g' val)) ds))+ f' (TypeClassDeclaration sa name args implies deps ds) = f (TypeClassDeclaration sa name args implies deps (fmap f' ds))+ f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = f (TypeInstanceDeclaration sa ch idx name cs className args (mapTypeInstanceBody (fmap f') ds))+ f' other = f other++ g' :: Expr -> Expr+ g' (Literal ss l) = g (Literal ss (lit g' l))+ g' (UnaryMinus ss v) = g (UnaryMinus ss (g' v))+ g' (BinaryNoParens op v1 v2) = g (BinaryNoParens (g' op) (g' v1) (g' v2))+ g' (Parens v) = g (Parens (g' v))+ g' (TypeClassDictionaryConstructorApp name v) = g (TypeClassDictionaryConstructorApp name (g' v))+ g' (Accessor prop v) = g (Accessor prop (g' v))+ g' (ObjectUpdate obj vs) = g (ObjectUpdate (g' obj) (fmap (fmap g') vs))+ g' (ObjectUpdateNested obj vs) = g (ObjectUpdateNested (g' obj) (fmap g' vs))+ g' (Abs binder v) = g (Abs (h' binder) (g' v))+ g' (App v1 v2) = g (App (g' v1) (g' v2))+ g' (Unused v) = g (Unused (g' v))+ g' (IfThenElse v1 v2 v3) = g (IfThenElse (g' v1) (g' v2) (g' v3))+ g' (Case vs alts) = g (Case (fmap g' vs) (fmap handleCaseAlternative alts))+ g' (TypedValue check v ty) = g (TypedValue check (g' v) ty)+ g' (Let w ds v) = g (Let w (fmap f' ds) (g' v))+ g' (Do m es) = g (Do m (fmap handleDoNotationElement es))+ g' (Ado m es v) = g (Ado m (fmap handleDoNotationElement es) (g' v))+ g' (PositionedValue pos com v) = g (PositionedValue pos com (g' v))+ g' other = g other++ h' :: Binder -> Binder+ h' (ConstructorBinder ss ctor bs) = h (ConstructorBinder ss ctor (fmap h' bs))+ h' (BinaryNoParensBinder b1 b2 b3) = h (BinaryNoParensBinder (h' b1) (h' b2) (h' b3))+ h' (ParensInBinder b) = h (ParensInBinder (h' b))+ h' (LiteralBinder ss l) = h (LiteralBinder ss (lit h' l))+ h' (NamedBinder ss name b) = h (NamedBinder ss name (h' b))+ h' (PositionedBinder pos com b) = h (PositionedBinder pos com (h' b))+ h' (TypedBinder t b) = h (TypedBinder t (h' b))+ h' other = h other++ lit :: (a -> a) -> Literal a -> Literal a+ lit go (ArrayLiteral as) = ArrayLiteral (fmap go as)+ lit go (ObjectLiteral as) = ObjectLiteral (fmap (fmap go) as)+ lit _ other = other++ handleCaseAlternative :: CaseAlternative -> CaseAlternative+ handleCaseAlternative ca =+ ca { caseAlternativeBinders = fmap h' (caseAlternativeBinders ca)+ , caseAlternativeResult = fmap (mapGuardedExpr handleGuard g') (caseAlternativeResult ca)+ }++ handleDoNotationElement :: DoNotationElement -> DoNotationElement+ handleDoNotationElement (DoNotationValue v) = DoNotationValue (g' v)+ handleDoNotationElement (DoNotationBind b v) = DoNotationBind (h' b) (g' v)+ handleDoNotationElement (DoNotationLet ds) = DoNotationLet (fmap f' ds)+ handleDoNotationElement (PositionedDoNotationElement pos com e) = PositionedDoNotationElement pos com (handleDoNotationElement e)++ handleGuard :: Guard -> Guard+ handleGuard (ConditionGuard e) = ConditionGuard (g' e)+ handleGuard (PatternGuard b e) = PatternGuard (h' b) (g' e)++everywhereOnValuesTopDownM+ :: forall m+ . (Monad m)+ => (Declaration -> m Declaration)+ -> (Expr -> m Expr)+ -> (Binder -> m Binder)+ -> ( Declaration -> m Declaration+ , Expr -> m Expr+ , Binder -> m Binder+ )+everywhereOnValuesTopDownM f g h = (f' <=< f, g' <=< g, h' <=< h)+ where++ f' :: Declaration -> m Declaration+ f' (DataBindingGroupDeclaration ds) = DataBindingGroupDeclaration <$> traverse (f' <=< f) ds+ f' (ValueDecl sa name nameKind bs val) =+ ValueDecl sa name nameKind <$> traverse (h' <=< h) bs <*> traverse (guardedExprM handleGuard (g' <=< g)) val+ f' (BindingGroupDeclaration ds) = BindingGroupDeclaration <$> traverse (\(name, nameKind, val) -> (name, nameKind, ) <$> (g val >>= g')) ds+ f' (TypeClassDeclaration sa name args implies deps ds) = TypeClassDeclaration sa name args implies deps <$> traverse (f' <=< f) ds+ f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse (f' <=< f)) ds+ f' (BoundValueDeclaration sa b expr) = BoundValueDeclaration sa <$> (h' <=< h) b <*> (g' <=< g) expr+ f' other = f other++ g' :: Expr -> m Expr+ g' (Literal ss l) = Literal ss <$> litM (g >=> g') l+ g' (UnaryMinus ss v) = UnaryMinus ss <$> (g v >>= g')+ g' (BinaryNoParens op v1 v2) = BinaryNoParens <$> (g op >>= g') <*> (g v1 >>= g') <*> (g v2 >>= g')+ g' (Parens v) = Parens <$> (g v >>= g')+ g' (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> (g v >>= g')+ g' (Accessor prop v) = Accessor prop <$> (g v >>= g')+ g' (ObjectUpdate obj vs) = ObjectUpdate <$> (g obj >>= g') <*> traverse (sndM (g' <=< g)) vs+ g' (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> (g obj >>= g') <*> traverse (g' <=< g) vs+ g' (Abs binder v) = Abs <$> (h binder >>= h') <*> (g v >>= g')+ g' (App v1 v2) = App <$> (g v1 >>= g') <*> (g v2 >>= g')+ g' (Unused v) = Unused <$> (g v >>= g')+ g' (IfThenElse v1 v2 v3) = IfThenElse <$> (g v1 >>= g') <*> (g v2 >>= g') <*> (g v3 >>= g')+ g' (Case vs alts) = Case <$> traverse (g' <=< g) vs <*> traverse handleCaseAlternative alts+ g' (TypedValue check v ty) = TypedValue check <$> (g v >>= g') <*> pure ty+ g' (Let w ds v) = Let w <$> traverse (f' <=< f) ds <*> (g v >>= g')+ g' (Do m es) = Do m <$> traverse handleDoNotationElement es+ g' (Ado m es v) = Ado m <$> traverse handleDoNotationElement es <*> (g v >>= g')+ g' (PositionedValue pos com v) = PositionedValue pos com <$> (g v >>= g')+ g' other = g other++ h' :: Binder -> m Binder+ h' (LiteralBinder ss l) = LiteralBinder ss <$> litM (h >=> h') l+ h' (ConstructorBinder ss ctor bs) = ConstructorBinder ss ctor <$> traverse (h' <=< h) bs+ h' (BinaryNoParensBinder b1 b2 b3) = BinaryNoParensBinder <$> (h b1 >>= h') <*> (h b2 >>= h') <*> (h b3 >>= h')+ h' (ParensInBinder b) = ParensInBinder <$> (h b >>= h')+ h' (NamedBinder ss name b) = NamedBinder ss name <$> (h b >>= h')+ h' (PositionedBinder pos com b) = PositionedBinder pos com <$> (h b >>= h')+ h' (TypedBinder t b) = TypedBinder t <$> (h b >>= h')+ h' other = h other++ handleCaseAlternative :: CaseAlternative -> m CaseAlternative+ handleCaseAlternative (CaseAlternative bs val) =+ CaseAlternative+ <$> traverse (h' <=< h) bs+ <*> traverse (guardedExprM handleGuard (g' <=< g)) val++ handleDoNotationElement :: DoNotationElement -> m DoNotationElement+ handleDoNotationElement (DoNotationValue v) = DoNotationValue <$> (g' <=< g) v+ handleDoNotationElement (DoNotationBind b v) = DoNotationBind <$> (h' <=< h) b <*> (g' <=< g) v+ handleDoNotationElement (DoNotationLet ds) = DoNotationLet <$> traverse (f' <=< f) ds+ handleDoNotationElement (PositionedDoNotationElement pos com e) = PositionedDoNotationElement pos com <$> handleDoNotationElement e++ handleGuard :: Guard -> m Guard+ handleGuard (ConditionGuard e) = ConditionGuard <$> (g' <=< g) e+ handleGuard (PatternGuard b e) = PatternGuard <$> (h' <=< h) b <*> (g' <=< g) e++everywhereOnValuesM+ :: forall m+ . (Monad m)+ => (Declaration -> m Declaration)+ -> (Expr -> m Expr)+ -> (Binder -> m Binder)+ -> ( Declaration -> m Declaration+ , Expr -> m Expr+ , Binder -> m Binder+ )+everywhereOnValuesM f g h = (f', g', h')+ where++ f' :: Declaration -> m Declaration+ f' (DataBindingGroupDeclaration ds) = (DataBindingGroupDeclaration <$> traverse f' ds) >>= f+ f' (ValueDecl sa name nameKind bs val) =+ ValueDecl sa name nameKind <$> traverse h' bs <*> traverse (guardedExprM handleGuard g') val >>= f+ f' (BindingGroupDeclaration ds) = (BindingGroupDeclaration <$> traverse (\(name, nameKind, val) -> (name, nameKind, ) <$> g' val) ds) >>= f+ f' (BoundValueDeclaration sa b expr) = (BoundValueDeclaration sa <$> h' b <*> g' expr) >>= f+ f' (TypeClassDeclaration sa name args implies deps ds) = (TypeClassDeclaration sa name args implies deps <$> traverse f' ds) >>= f+ f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = (TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse f') ds) >>= f+ f' other = f other++ g' :: Expr -> m Expr+ g' (Literal ss l) = (Literal ss <$> litM g' l) >>= g+ g' (UnaryMinus ss v) = (UnaryMinus ss <$> g' v) >>= g+ g' (BinaryNoParens op v1 v2) = (BinaryNoParens <$> g' op <*> g' v1 <*> g' v2) >>= g+ g' (Parens v) = (Parens <$> g' v) >>= g+ g' (TypeClassDictionaryConstructorApp name v) = (TypeClassDictionaryConstructorApp name <$> g' v) >>= g+ g' (Accessor prop v) = (Accessor prop <$> g' v) >>= g+ g' (ObjectUpdate obj vs) = (ObjectUpdate <$> g' obj <*> traverse (sndM g') vs) >>= g+ g' (ObjectUpdateNested obj vs) = (ObjectUpdateNested <$> g' obj <*> traverse g' vs) >>= g+ g' (Abs binder v) = (Abs <$> h' binder <*> g' v) >>= g+ g' (App v1 v2) = (App <$> g' v1 <*> g' v2) >>= g+ g' (Unused v) = (Unused <$> g' v) >>= g+ g' (IfThenElse v1 v2 v3) = (IfThenElse <$> g' v1 <*> g' v2 <*> g' v3) >>= g+ g' (Case vs alts) = (Case <$> traverse g' vs <*> traverse handleCaseAlternative alts) >>= g+ g' (TypedValue check v ty) = (TypedValue check <$> g' v <*> pure ty) >>= g+ g' (Let w ds v) = (Let w <$> traverse f' ds <*> g' v) >>= g+ g' (Do m es) = (Do m <$> traverse handleDoNotationElement es) >>= g+ g' (Ado m es v) = (Ado m <$> traverse handleDoNotationElement es <*> g' v) >>= g+ g' (PositionedValue pos com v) = (PositionedValue pos com <$> g' v) >>= g+ g' other = g other++ h' :: Binder -> m Binder+ h' (LiteralBinder ss l) = (LiteralBinder ss <$> litM h' l) >>= h+ h' (ConstructorBinder ss ctor bs) = (ConstructorBinder ss ctor <$> traverse h' bs) >>= h+ h' (BinaryNoParensBinder b1 b2 b3) = (BinaryNoParensBinder <$> h' b1 <*> h' b2 <*> h' b3) >>= h+ h' (ParensInBinder b) = (ParensInBinder <$> h' b) >>= h+ h' (NamedBinder ss name b) = (NamedBinder ss name <$> h' b) >>= h+ h' (PositionedBinder pos com b) = (PositionedBinder pos com <$> h' b) >>= h+ h' (TypedBinder t b) = (TypedBinder t <$> h' b) >>= h+ h' other = h other++ handleCaseAlternative :: CaseAlternative -> m CaseAlternative+ handleCaseAlternative (CaseAlternative bs val) =+ CaseAlternative+ <$> traverse h' bs+ <*> traverse (guardedExprM handleGuard g') val++ handleDoNotationElement :: DoNotationElement -> m DoNotationElement+ handleDoNotationElement (DoNotationValue v) = DoNotationValue <$> g' v+ handleDoNotationElement (DoNotationBind b v) = DoNotationBind <$> h' b <*> g' v+ handleDoNotationElement (DoNotationLet ds) = DoNotationLet <$> traverse f' ds+ handleDoNotationElement (PositionedDoNotationElement pos com e) = PositionedDoNotationElement pos com <$> handleDoNotationElement e++ handleGuard :: Guard -> m Guard+ handleGuard (ConditionGuard e) = ConditionGuard <$> g' e+ handleGuard (PatternGuard b e) = PatternGuard <$> h' b <*> g' e++everythingOnValues+ :: forall r+ . (r -> r -> r)+ -> (Declaration -> r)+ -> (Expr -> r)+ -> (Binder -> r)+ -> (CaseAlternative -> r)+ -> (DoNotationElement -> r)+ -> ( Declaration -> r+ , Expr -> r+ , Binder -> r+ , CaseAlternative -> r+ , DoNotationElement -> r+ )+everythingOnValues (<>.) f g h i j = (f', g', h', i', j')+ where++ f' :: Declaration -> r+ f' d@(DataBindingGroupDeclaration ds) = foldl (<>.) (f d) (fmap f' ds)+ f' d@(ValueDeclaration vd) = foldl (<>.) (f d) (fmap h' (valdeclBinders vd) ++ concatMap (\(GuardedExpr grd v) -> fmap k' grd ++ [g' v]) (valdeclExpression vd))+ f' d@(BindingGroupDeclaration ds) = foldl (<>.) (f d) (fmap (\(_, _, val) -> g' val) ds)+ f' d@(TypeClassDeclaration _ _ _ _ _ ds) = foldl (<>.) (f d) (fmap f' ds)+ f' d@(TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>.) (f d) (fmap f' ds)+ f' d@(BoundValueDeclaration _ b expr) = f d <>. h' b <>. g' expr+ f' d = f d++ g' :: Expr -> r+ g' v@(Literal _ l) = lit (g v) g' l+ g' v@(UnaryMinus _ v1) = g v <>. g' v1+ g' v@(BinaryNoParens op v1 v2) = g v <>. g' op <>. g' v1 <>. g' v2+ g' v@(Parens v1) = g v <>. g' v1+ g' v@(TypeClassDictionaryConstructorApp _ v1) = g v <>. g' v1+ g' v@(Accessor _ v1) = g v <>. g' v1+ g' v@(ObjectUpdate obj vs) = foldl (<>.) (g v <>. g' obj) (fmap (g' . snd) vs)+ g' v@(ObjectUpdateNested obj vs) = foldl (<>.) (g v <>. g' obj) (fmap g' vs)+ g' v@(Abs b v1) = g v <>. h' b <>. g' v1+ g' v@(App v1 v2) = g v <>. g' v1 <>. g' v2+ g' v@(Unused v1) = g v <>. g' v1+ g' v@(IfThenElse v1 v2 v3) = g v <>. g' v1 <>. g' v2 <>. g' v3+ g' v@(Case vs alts) = foldl (<>.) (foldl (<>.) (g v) (fmap g' vs)) (fmap i' alts)+ g' v@(TypedValue _ v1 _) = g v <>. g' v1+ g' v@(Let _ ds v1) = foldl (<>.) (g v) (fmap f' ds) <>. g' v1+ g' v@(Do _ es) = foldl (<>.) (g v) (fmap j' es)+ g' v@(Ado _ es v1) = foldl (<>.) (g v) (fmap j' es) <>. g' v1+ g' v@(PositionedValue _ _ v1) = g v <>. g' v1+ g' v = g v++ h' :: Binder -> r+ h' b@(LiteralBinder _ l) = lit (h b) h' l+ h' b@(ConstructorBinder _ _ bs) = foldl (<>.) (h b) (fmap h' bs)+ h' b@(BinaryNoParensBinder b1 b2 b3) = h b <>. h' b1 <>. h' b2 <>. h' b3+ h' b@(ParensInBinder b1) = h b <>. h' b1+ h' b@(NamedBinder _ _ b1) = h b <>. h' b1+ h' b@(PositionedBinder _ _ b1) = h b <>. h' b1+ h' b@(TypedBinder _ b1) = h b <>. h' b1+ h' b = h b++ lit :: r -> (a -> r) -> Literal a -> r+ lit r go (ArrayLiteral as) = foldl (<>.) r (fmap go as)+ lit r go (ObjectLiteral as) = foldl (<>.) r (fmap (go . snd) as)+ lit r _ _ = r++ i' :: CaseAlternative -> r+ i' ca@(CaseAlternative bs gs) =+ foldl (<>.) (i ca) (fmap h' bs ++ concatMap (\(GuardedExpr grd val) -> fmap k' grd ++ [g' val]) gs)++ j' :: DoNotationElement -> r+ j' e@(DoNotationValue v) = j e <>. g' v+ j' e@(DoNotationBind b v) = j e <>. h' b <>. g' v+ j' e@(DoNotationLet ds) = foldl (<>.) (j e) (fmap f' ds)+ j' e@(PositionedDoNotationElement _ _ e1) = j e <>. j' e1++ k' :: Guard -> r+ k' (ConditionGuard e) = g' e+ k' (PatternGuard b e) = h' b <>. g' e++everythingWithContextOnValues+ :: forall s r+ . s+ -> r+ -> (r -> r -> r)+ -> (s -> Declaration -> (s, r))+ -> (s -> Expr -> (s, r))+ -> (s -> Binder -> (s, r))+ -> (s -> CaseAlternative -> (s, r))+ -> (s -> DoNotationElement -> (s, r))+ -> ( Declaration -> r+ , Expr -> r+ , Binder -> r+ , CaseAlternative -> r+ , DoNotationElement -> r)+everythingWithContextOnValues s0 r0 (<>.) f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j'' s0)+ where++ f'' :: s -> Declaration -> r+ f'' s d = let (s', r) = f s d in r <>. f' s' d++ f' :: s -> Declaration -> r+ f' s (DataBindingGroupDeclaration ds) = foldl (<>.) r0 (fmap (f'' s) ds)+ f' s (ValueDeclaration vd) = foldl (<>.) r0 (fmap (h'' s) (valdeclBinders vd) ++ concatMap (\(GuardedExpr grd v) -> fmap (k' s) grd ++ [g'' s v]) (valdeclExpression vd))+ f' s (BindingGroupDeclaration ds) = foldl (<>.) r0 (fmap (\(_, _, val) -> g'' s val) ds)+ f' s (TypeClassDeclaration _ _ _ _ _ ds) = foldl (<>.) r0 (fmap (f'' s) ds)+ f' s (TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>.) r0 (fmap (f'' s) ds)+ f' _ _ = r0++ g'' :: s -> Expr -> r+ g'' s v = let (s', r) = g s v in r <>. g' s' v++ g' :: s -> Expr -> r+ g' s (Literal _ l) = lit g'' s l+ g' s (UnaryMinus _ v1) = g'' s v1+ g' s (BinaryNoParens op v1 v2) = g'' s op <>. g'' s v1 <>. g'' s v2+ g' s (Parens v1) = g'' s v1+ g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1+ g' s (Accessor _ v1) = g'' s v1+ g' s (ObjectUpdate obj vs) = foldl (<>.) (g'' s obj) (fmap (g'' s . snd) vs)+ g' s (ObjectUpdateNested obj vs) = foldl (<>.) (g'' s obj) (fmap (g'' s) vs)+ g' s (Abs binder v1) = h'' s binder <>. g'' s v1+ g' s (App v1 v2) = g'' s v1 <>. g'' s v2+ g' s (Unused v) = g'' s v+ g' s (IfThenElse v1 v2 v3) = g'' s v1 <>. g'' s v2 <>. g'' s v3+ g' s (Case vs alts) = foldl (<>.) (foldl (<>.) r0 (fmap (g'' s) vs)) (fmap (i'' s) alts)+ g' s (TypedValue _ v1 _) = g'' s v1+ g' s (Let _ ds v1) = foldl (<>.) r0 (fmap (f'' s) ds) <>. g'' s v1+ g' s (Do _ es) = foldl (<>.) r0 (fmap (j'' s) es)+ g' s (Ado _ es v1) = foldl (<>.) r0 (fmap (j'' s) es) <>. g'' s v1+ g' s (PositionedValue _ _ v1) = g'' s v1+ g' _ _ = r0++ h'' :: s -> Binder -> r+ h'' s b = let (s', r) = h s b in r <>. h' s' b++ h' :: s -> Binder -> r+ h' s (LiteralBinder _ l) = lit h'' s l+ h' s (ConstructorBinder _ _ bs) = foldl (<>.) r0 (fmap (h'' s) bs)+ h' s (BinaryNoParensBinder b1 b2 b3) = h'' s b1 <>. h'' s b2 <>. h'' s b3+ h' s (ParensInBinder b) = h'' s b+ h' s (NamedBinder _ _ b1) = h'' s b1+ h' s (PositionedBinder _ _ b1) = h'' s b1+ h' s (TypedBinder _ b1) = h'' s b1+ h' _ _ = r0++ lit :: (s -> a -> r) -> s -> Literal a -> r+ lit go s (ArrayLiteral as) = foldl (<>.) r0 (fmap (go s) as)+ lit go s (ObjectLiteral as) = foldl (<>.) r0 (fmap (go s . snd) as)+ lit _ _ _ = r0++ i'' :: s -> CaseAlternative -> r+ i'' s ca = let (s', r) = i s ca in r <>. i' s' ca++ i' :: s -> CaseAlternative -> r+ i' s (CaseAlternative bs gs) = foldl (<>.) r0 (fmap (h'' s) bs ++ concatMap (\(GuardedExpr grd val) -> fmap (k' s) grd ++ [g'' s val]) gs)++ j'' :: s -> DoNotationElement -> r+ j'' s e = let (s', r) = j s e in r <>. j' s' e++ j' :: s -> DoNotationElement -> r+ j' s (DoNotationValue v) = g'' s v+ j' s (DoNotationBind b v) = h'' s b <>. g'' s v+ j' s (DoNotationLet ds) = foldl (<>.) r0 (fmap (f'' s) ds)+ j' s (PositionedDoNotationElement _ _ e1) = j'' s e1++ k' :: s -> Guard -> r+ k' s (ConditionGuard e) = g'' s e+ k' s (PatternGuard b e) = h'' s b <>. g'' s e++everywhereWithContextOnValuesM+ :: forall m s+ . (Monad m)+ => s+ -> (s -> Declaration -> m (s, Declaration))+ -> (s -> Expr -> m (s, Expr))+ -> (s -> Binder -> m (s, Binder))+ -> (s -> CaseAlternative -> m (s, CaseAlternative))+ -> (s -> DoNotationElement -> m (s, DoNotationElement))+ -> ( Declaration -> m Declaration+ , Expr -> m Expr+ , Binder -> m Binder+ , CaseAlternative -> m CaseAlternative+ , DoNotationElement -> m DoNotationElement+ )+everywhereWithContextOnValuesM s0 f g h i j = (f'' s0, g'' s0, h'' s0, i'' s0, j'' s0)+ where+ f'' s = uncurry f' <=< f s++ f' s (DataBindingGroupDeclaration ds) = DataBindingGroupDeclaration <$> traverse (f'' s) ds+ f' s (ValueDecl sa name nameKind bs val) =+ ValueDecl sa name nameKind <$> traverse (h'' s) bs <*> traverse (guardedExprM (k' s) (g'' s)) val+ f' s (BindingGroupDeclaration ds) = BindingGroupDeclaration <$> traverse (thirdM (g'' s)) ds+ f' s (TypeClassDeclaration sa name args implies deps ds) = TypeClassDeclaration sa name args implies deps <$> traverse (f'' s) ds+ f' s (TypeInstanceDeclaration sa ch idx name cs className args ds) = TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse (f'' s)) ds+ f' _ other = return other++ g'' s = uncurry g' <=< g s++ g' s (Literal ss l) = Literal ss <$> lit g'' s l+ g' s (UnaryMinus ss v) = UnaryMinus ss <$> g'' s v+ g' s (BinaryNoParens op v1 v2) = BinaryNoParens <$> g'' s op <*> g'' s v1 <*> g'' s v2+ g' s (Parens v) = Parens <$> g'' s v+ g' s (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> g'' s v+ g' s (Accessor prop v) = Accessor prop <$> g'' s v+ g' s (ObjectUpdate obj vs) = ObjectUpdate <$> g'' s obj <*> traverse (sndM (g'' s)) vs+ g' s (ObjectUpdateNested obj vs) = ObjectUpdateNested <$> g'' s obj <*> traverse (g'' s) vs+ g' s (Abs binder v) = Abs <$> h' s binder <*> g'' s v+ g' s (App v1 v2) = App <$> g'' s v1 <*> g'' s v2+ g' s (Unused v) = Unused <$> g'' s v+ g' s (IfThenElse v1 v2 v3) = IfThenElse <$> g'' s v1 <*> g'' s v2 <*> g'' s v3+ g' s (Case vs alts) = Case <$> traverse (g'' s) vs <*> traverse (i'' s) alts+ g' s (TypedValue check v ty) = TypedValue check <$> g'' s v <*> pure ty+ g' s (Let w ds v) = Let w <$> traverse (f'' s) ds <*> g'' s v+ g' s (Do m es) = Do m <$> traverse (j'' s) es+ g' s (Ado m es v) = Ado m <$> traverse (j'' s) es <*> g'' s v+ g' s (PositionedValue pos com v) = PositionedValue pos com <$> g'' s v+ g' _ other = return other++ h'' s = uncurry h' <=< h s++ h' s (LiteralBinder ss l) = LiteralBinder ss <$> lit h'' s l+ h' s (ConstructorBinder ss ctor bs) = ConstructorBinder ss ctor <$> traverse (h'' s) bs+ h' s (BinaryNoParensBinder b1 b2 b3) = BinaryNoParensBinder <$> h'' s b1 <*> h'' s b2 <*> h'' s b3+ h' s (ParensInBinder b) = ParensInBinder <$> h'' s b+ h' s (NamedBinder ss name b) = NamedBinder ss name <$> h'' s b+ h' s (PositionedBinder pos com b) = PositionedBinder pos com <$> h'' s b+ h' s (TypedBinder t b) = TypedBinder t <$> h'' s b+ h' _ other = return other++ lit :: (s -> a -> m a) -> s -> Literal a -> m (Literal a)+ lit go s (ArrayLiteral as) = ArrayLiteral <$> traverse (go s) as+ lit go s (ObjectLiteral as) = ObjectLiteral <$> traverse (sndM (go s)) as+ lit _ _ other = return other++ i'' s = uncurry i' <=< i s++ i' s (CaseAlternative bs val) = CaseAlternative <$> traverse (h'' s) bs <*> traverse (guardedExprM (k' s) (g'' s)) val++ j'' s = uncurry j' <=< j s++ j' s (DoNotationValue v) = DoNotationValue <$> g'' s v+ j' s (DoNotationBind b v) = DoNotationBind <$> h'' s b <*> g'' s v+ j' s (DoNotationLet ds) = DoNotationLet <$> traverse (f'' s) ds+ j' s (PositionedDoNotationElement pos com e1) = PositionedDoNotationElement pos com <$> j'' s e1++ k' s (ConditionGuard e) = ConditionGuard <$> g'' s e+ k' s (PatternGuard b e) = PatternGuard <$> h'' s b <*> g'' s e++data ScopedIdent = LocalIdent Ident | ToplevelIdent Ident+ deriving (Show, Eq, Ord)++inScope :: Ident -> S.Set ScopedIdent -> Bool+inScope i s = (LocalIdent i `S.member` s) || (ToplevelIdent i `S.member` s)++everythingWithScope+ :: forall r+ . (Monoid r)+ => (S.Set ScopedIdent -> Declaration -> r)+ -> (S.Set ScopedIdent -> Expr -> r)+ -> (S.Set ScopedIdent -> Binder -> r)+ -> (S.Set ScopedIdent -> CaseAlternative -> r)+ -> (S.Set ScopedIdent -> DoNotationElement -> r)+ -> ( S.Set ScopedIdent -> Declaration -> r+ , S.Set ScopedIdent -> Expr -> r+ , S.Set ScopedIdent -> Binder -> r+ , S.Set ScopedIdent -> CaseAlternative -> r+ , S.Set ScopedIdent -> DoNotationElement -> r+ )+everythingWithScope f g h i j = (f'', g'', h'', i'', \s -> snd . j'' s)+ where+ f'' :: S.Set ScopedIdent -> Declaration -> r+ f'' s a = f s a <> f' s a++ f' :: S.Set ScopedIdent -> Declaration -> r+ f' s (DataBindingGroupDeclaration ds) =+ let s' = S.union s (S.fromList (map ToplevelIdent (mapMaybe getDeclIdent (NEL.toList ds))))+ in foldMap (f'' s') ds+ f' s (ValueDecl _ name _ bs val) =+ let s' = S.insert (ToplevelIdent name) s+ s'' = S.union s' (S.fromList (concatMap localBinderNames bs))+ in foldMap (h'' s') bs <> foldMap (l' s'') val+ f' s (BindingGroupDeclaration ds) =+ let s' = S.union s (S.fromList (NEL.toList (fmap (\((_, name), _, _) -> ToplevelIdent name) ds)))+ in foldMap (\(_, _, val) -> g'' s' val) ds+ f' s (TypeClassDeclaration _ _ _ _ _ ds) = foldMap (f'' s) ds+ f' s (TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldMap (f'' s) ds+ f' _ _ = mempty++ g'' :: S.Set ScopedIdent -> Expr -> r+ g'' s a = g s a <> g' s a++ g' :: S.Set ScopedIdent -> Expr -> r+ g' s (Literal _ l) = lit g'' s l+ g' s (UnaryMinus _ v1) = g'' s v1+ g' s (BinaryNoParens op v1 v2) = g'' s op <> g'' s v1 <> g'' s v2+ g' s (Parens v1) = g'' s v1+ g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1+ g' s (Accessor _ v1) = g'' s v1+ g' s (ObjectUpdate obj vs) = g'' s obj <> foldMap (g'' s . snd) vs+ g' s (ObjectUpdateNested obj vs) = g'' s obj <> foldMap (g'' s) vs+ g' s (Abs b v1) =+ let s' = S.union (S.fromList (localBinderNames b)) s+ in h'' s b <> g'' s' v1+ g' s (App v1 v2) = g'' s v1 <> g'' s v2+ g' s (Unused v) = g'' s v+ g' s (IfThenElse v1 v2 v3) = g'' s v1 <> g'' s v2 <> g'' s v3+ g' s (Case vs alts) = foldMap (g'' s) vs <> foldMap (i'' s) alts+ g' s (TypedValue _ v1 _) = g'' s v1+ g' s (Let _ ds v1) =+ let s' = S.union s (S.fromList (map LocalIdent (mapMaybe getDeclIdent ds)))+ in foldMap (f'' s') ds <> g'' s' v1+ g' s (Do _ es) = fold . snd . mapAccumL j'' s $ es+ g' s (Ado _ es v1) =+ let s' = S.union s (foldMap (fst . j'' s) es)+ in g'' s' v1+ g' s (PositionedValue _ _ v1) = g'' s v1+ g' _ _ = mempty++ h'' :: S.Set ScopedIdent -> Binder -> r+ h'' s a = h s a <> h' s a++ h' :: S.Set ScopedIdent -> Binder -> r+ h' s (LiteralBinder _ l) = lit h'' s l+ h' s (ConstructorBinder _ _ bs) = foldMap (h'' s) bs+ h' s (BinaryNoParensBinder b1 b2 b3) = foldMap (h'' s) [b1, b2, b3]+ h' s (ParensInBinder b) = h'' s b+ h' s (NamedBinder _ name b1) = h'' (S.insert (LocalIdent name) s) b1+ h' s (PositionedBinder _ _ b1) = h'' s b1+ h' s (TypedBinder _ b1) = h'' s b1+ h' _ _ = mempty++ lit :: (S.Set ScopedIdent -> a -> r) -> S.Set ScopedIdent -> Literal a -> r+ lit go s (ArrayLiteral as) = foldMap (go s) as+ lit go s (ObjectLiteral as) = foldMap (go s . snd) as+ lit _ _ _ = mempty++ i'' :: S.Set ScopedIdent -> CaseAlternative -> r+ i'' s a = i s a <> i' s a++ i' :: S.Set ScopedIdent -> CaseAlternative -> r+ i' s (CaseAlternative bs gs) =+ let s' = S.union s (S.fromList (concatMap localBinderNames bs))+ in foldMap (h'' s) bs <> foldMap (l' s') gs++ j'' :: S.Set ScopedIdent -> DoNotationElement -> (S.Set ScopedIdent, r)+ j'' s a = let (s', r) = j' s a in (s', j s a <> r)++ j' :: S.Set ScopedIdent -> DoNotationElement -> (S.Set ScopedIdent, r)+ j' s (DoNotationValue v) = (s, g'' s v)+ j' s (DoNotationBind b v) =+ let s' = S.union (S.fromList (localBinderNames b)) s+ in (s', h'' s b <> g'' s v)+ j' s (DoNotationLet ds) =+ let s' = S.union s (S.fromList (map LocalIdent (mapMaybe getDeclIdent ds)))+ in (s', foldMap (f'' s') ds)+ j' s (PositionedDoNotationElement _ _ e1) = j'' s e1++ k' :: S.Set ScopedIdent -> Guard -> (S.Set ScopedIdent, r)+ k' s (ConditionGuard e) = (s, g'' s e)+ k' s (PatternGuard b e) =+ let s' = S.union (S.fromList (localBinderNames b)) s+ in (s', h'' s b <> g'' s' e)++ l' s (GuardedExpr [] e) = g'' s e+ l' s (GuardedExpr (grd:gs) e) =+ let (s', r) = k' s grd+ in r <> l' s' (GuardedExpr gs e)++ getDeclIdent :: Declaration -> Maybe Ident+ getDeclIdent (ValueDeclaration vd) = Just (valdeclIdent vd)+ getDeclIdent (TypeDeclaration td) = Just (tydeclIdent td)+ getDeclIdent _ = Nothing++ localBinderNames = map LocalIdent . binderNames++accumTypes+ :: (Monoid r)+ => (SourceType -> r)+ -> ( Declaration -> r+ , Expr -> r+ , Binder -> r+ , CaseAlternative -> r+ , DoNotationElement -> r+ )+accumTypes f = everythingOnValues mappend forDecls forValues forBinders (const mempty) (const mempty)+ where+ forDecls (DataDeclaration _ _ _ args dctors) =+ foldMap (foldMap f . snd) args <>+ foldMap (foldMap (f . snd) . dataCtorFields) dctors+ forDecls (ExternDataDeclaration _ _ ty) = f ty+ forDecls (ExternDeclaration _ _ ty) = f ty+ forDecls (TypeClassDeclaration _ _ args implies _ _) =+ foldMap (foldMap (foldMap f)) args <>+ foldMap (foldMap f . constraintArgs) implies+ forDecls (TypeInstanceDeclaration _ _ _ _ cs _ tys _) =+ foldMap (foldMap f . constraintArgs) cs <> foldMap f tys+ forDecls (TypeSynonymDeclaration _ _ args ty) =+ foldMap (foldMap f . snd) args <>+ f ty+ forDecls (KindDeclaration _ _ _ ty) = f ty+ forDecls (TypeDeclaration td) = f (tydeclType td)+ forDecls _ = mempty++ forValues (TypeClassDictionary c _ _) = foldMap f (constraintArgs c)+ forValues (DeferredDictionary _ tys) = foldMap f tys+ forValues (TypedValue _ _ ty) = f ty+ forValues _ = mempty++ forBinders (TypedBinder ty _) = f ty+ forBinders _ = mempty++-- |+-- Map a function over type annotations appearing inside a value+--+overTypes :: (SourceType -> SourceType) -> Expr -> Expr+overTypes f = let (_, f', _) = everywhereOnValues id g id in f'+ where+ g :: Expr -> Expr+ g (TypedValue checkTy val t) = TypedValue checkTy val (f t)+ g (TypeClassDictionary c sco hints) =+ TypeClassDictionary+ (mapConstraintArgs (fmap f) c)+ (updateCtx sco)+ hints+ g other = other+ updateDict fn dict = dict { tcdInstanceTypes = fn (tcdInstanceTypes dict) }+ updateScope = fmap . fmap . fmap . fmap $ updateDict $ fmap f+ updateCtx = M.alter updateScope Nothing
src/Language/PureScript/CST/Convert.hs view
@@ -15,7 +15,7 @@ , comments ) where -import Prelude+import Prelude hiding (take) import Data.Bifunctor (bimap, first) import Data.Foldable (foldl', toList)@@ -24,13 +24,14 @@ import Data.Maybe (isJust, fromJust, mapMaybe) import qualified Data.Text as Text import qualified Language.PureScript.AST as AST+import Language.PureScript.AST.Declarations.ChainId (mkChainId) import qualified Language.PureScript.AST.SourcePos as Pos import qualified Language.PureScript.Comments as C import Language.PureScript.Crash (internalError) import qualified Language.PureScript.Environment as Env import qualified Language.PureScript.Label as L import qualified Language.PureScript.Names as N-import Language.PureScript.PSString (mkString)+import Language.PureScript.PSString (mkString, prettyPrintStringJS) import qualified Language.PureScript.Types as T import Language.PureScript.CST.Positions import Language.PureScript.CST.Print (printToken)@@ -39,8 +40,8 @@ comment :: Comment a -> Maybe C.Comment comment = \case Comment t- | Text.isPrefixOf "{-" t -> Just $ C.BlockComment $ Text.drop 2 $ Text.dropEnd 2 t- | Text.isPrefixOf "--" t -> Just $ C.LineComment $ Text.drop 2 t+ | "{-" `Text.isPrefixOf` t -> Just $ C.BlockComment $ Text.drop 2 $ Text.dropEnd 2 t+ | "--" `Text.isPrefixOf` t -> Just $ C.LineComment $ Text.drop 2 t _ -> Nothing comments :: [Comment a] -> [C.Comment]@@ -120,7 +121,7 @@ TypeHole _ a -> T.TypeWildcard (sourceName fileName a) . Just . getIdent $ nameValue a TypeString _ a b ->- T.TypeLevelString (sourceAnnCommented fileName a a) $ b+ T.TypeLevelString (sourceAnnCommented fileName a a) b TypeRow _ (Wrapped _ row b) -> goRow row b TypeRecord _ (Wrapped a row b) -> do@@ -468,24 +469,24 @@ (goSig <$> maybe [] (NE.toList . snd) bd) DeclInstanceChain _ insts -> do let- instName (Instance (InstanceHead _ a _ _ _ _) _) = ident $ nameValue a- chainId = instName <$> toList insts- goInst ix inst@(Instance (InstanceHead _ name _ ctrs cls args) bd) = do+ chainId = mkChainId fileName $ startSourcePos $ instKeyword $ instHead $ sepHead insts+ goInst ix inst@(Instance (InstanceHead _ nameSep ctrs cls args) bd) = do let ann' = uncurry (sourceAnnCommented fileName) $ instanceRange inst AST.TypeInstanceDeclaration ann' chainId ix- (ident $ nameValue name)+ (mkPartialInstanceName nameSep cls args) (convertConstraint fileName <$> maybe [] (toList . fst) ctrs) (qualified cls) (convertType fileName <$> args) (AST.ExplicitInstance $ goInstanceBinding <$> maybe [] (NE.toList . snd) bd) uncurry goInst <$> zip [0..] (toList insts)- DeclDerive _ _ new (InstanceHead _ name _ ctrs cls args) -> do+ DeclDerive _ _ new (InstanceHead kw nameSep ctrs cls args) -> do let- name' = ident $ nameValue name+ chainId = mkChainId fileName $ startSourcePos kw+ name' = mkPartialInstanceName nameSep cls args instTy | isJust new = AST.NewtypeInstance | otherwise = AST.DerivedInstance- pure $ AST.TypeInstanceDeclaration ann [name'] 0 name'+ pure $ AST.TypeInstanceDeclaration ann chainId 0 name' (convertConstraint fileName <$> maybe [] (toList . fst) ctrs) (qualified cls) (convertType fileName <$> args)@@ -530,6 +531,55 @@ ann = uncurry (sourceAnnCommented fileName) $ declRange decl + startSourcePos :: SourceToken -> Pos.SourcePos+ startSourcePos = sourcePos . srcStart . tokRange . tokAnn++ mkPartialInstanceName :: Maybe (Name Ident, SourceToken) -> QualifiedName (N.ProperName 'N.ClassName) -> [Type a] -> Either Text.Text N.Ident+ mkPartialInstanceName nameSep cls args =+ maybe (Left genName) (Right . ident . nameValue . fst) nameSep+ where+ -- truncate to 25 chars to reduce verbosity+ -- of name and still keep it readable+ -- unique identifier will be appended to this name+ -- in desugaring proces+ genName :: Text.Text+ genName = "$_" <> Text.take 25 (className <> typeArgs) <> "_"++ className :: Text.Text+ className = N.runProperName $ qualName cls++ typeArgs :: Text.Text+ typeArgs = foldMap argName args++ argName :: Type a -> Text.Text+ argName = \case+ -- These are only useful to disambiguate between overlapping instances+ -- but they’re disallowed outside of instance chains. Since we’re+ -- avoiding name collisions with unique identifiers anyway,+ -- we don't need to render this constructor.+ TypeVar{} -> ""+ TypeConstructor _ qn -> N.runProperName $ qualName qn+ TypeOpName _ qn -> N.runOpName $ qualName qn+ TypeString _ _ ps -> prettyPrintStringJS ps++ -- Typed holes are disallowed in instance heads+ TypeHole{} -> ""+ TypeParens _ t -> argName $ wrpValue t+ TypeKinded _ t1 _ t2 -> argName t1 <> argName t2+ TypeRecord _ _ -> "Record"+ TypeRow _ _ -> "Row"+ TypeArrName _ _ -> "Function"+ TypeWildcard{} -> "_"++ -- Polytypes are disallowed in instance heads+ TypeForall{} -> ""+ TypeApp _ t1 t2 -> argName t1 <> argName t2+ TypeOp _ t1 op t2 ->+ argName t1 <> N.runOpName (qualName op) <> argName t2+ TypeArr _ t1 _ t2 -> argName t1 <> "Function" <> argName t2+ TypeConstrained{} -> ""+ TypeUnaryRow{} -> "Row"+ goTypeVar = \case TypeVarKinded (Wrapped _ (Labeled x _ y) _) -> (getIdent $ nameValue x, Just $ convertType fileName y) TypeVarName x -> (getIdent $ nameValue x, Nothing)@@ -564,7 +614,7 @@ ann = uncurry (sourceAnnCommented fileName) $ importDeclRange decl importTy = case mbNames of Nothing -> AST.Implicit- Just (hiding, (Wrapped _ imps _)) -> do+ Just (hiding, Wrapped _ imps _) -> do let imps' = convertImport fileName <$> toList imps if isJust hiding then AST.Hiding imps'
src/Language/PureScript/CST/Errors.hs view
@@ -76,7 +76,7 @@ type ParserWarning = ParserErrorInfo ParserWarningType prettyPrintError :: ParserError -> String-prettyPrintError pe@(ParserErrorInfo { errRange }) =+prettyPrintError pe@ParserErrorInfo { errRange } = prettyPrintErrorMessage pe <> " at " <> errPos where errPos = case errRange of@@ -84,7 +84,7 @@ "line " <> show line <> ", column " <> show col prettyPrintErrorMessage :: ParserError -> String-prettyPrintErrorMessage (ParserErrorInfo {..}) = case errType of+prettyPrintErrorMessage ParserErrorInfo {..} = case errType of ErrWildcardInType -> "Unexpected wildcard in type; type wildcards are only allowed in value annotations" ErrConstraintInKind ->@@ -182,7 +182,7 @@ "U+" <> map toUpper (printf "%0.4x" (fromEnum x)) prettyPrintWarningMessage :: ParserWarning -> String-prettyPrintWarningMessage (ParserErrorInfo {..}) = case errType of+prettyPrintWarningMessage ParserErrorInfo {..} = case errType of WarnDeprecatedRowSyntax -> "Unary '#' syntax for row kinds is deprecated and will be removed in a future release. Use the 'Row' kind instead." WarnDeprecatedForeignKindSyntax ->
src/Language/PureScript/CST/Flatten.hs view
@@ -46,13 +46,12 @@ flattenInstanceHead a <> foldMap (\(c, d) -> pure c <> foldMap flattenInstanceBinding d) b flattenInstanceHead :: InstanceHead a -> DList SourceToken-flattenInstanceHead (InstanceHead a b c d e f) =+flattenInstanceHead (InstanceHead a b c d e) = pure a <>- flattenName b <>- pure c <>- foldMap (\(g, h) -> flattenOneOrDelimited flattenConstraint g <> pure h) d <>- flattenQualifiedName e <>- foldMap flattenType f+ foldMap (\(n, s) -> flattenName n <> pure s) b <>+ foldMap (\(g, h) -> flattenOneOrDelimited flattenConstraint g <> pure h) c <>+ flattenQualifiedName d <>+ foldMap flattenType e flattenInstanceBinding :: InstanceBinding a -> DList SourceToken flattenInstanceBinding = \case
src/Language/PureScript/CST/Lexer.hs view
@@ -70,7 +70,7 @@ Parser lexK = tokenAndComments - go state@(LexState {..}) =+ go state@LexState {..} = lexK lexSource onError onSuccess where onError lexSource' err = do@@ -204,7 +204,7 @@ comment = isBlockComment >>= \case Just True -> Just <$> blockComment "{-" Just False -> Just <$> lineComment "--"- Nothing -> pure $ Nothing+ Nothing -> pure Nothing lineComment acc = do comm <- nextWhile (\c -> c /= '\r' && c /= '\n')@@ -332,7 +332,7 @@ operator : symbolChar+ -}- operator :: [Text] -> [Char] -> Lexer Token+ operator :: [Text] -> String -> Lexer Token operator qual pre = do rest <- nextWhile isSymbolChar pure . TokOperator (reverse qual) $ Text.pack pre <> rest@@ -417,7 +417,7 @@ Just ch -> next $> (Text.singleton ch, ch) Nothing ->- throw $ ErrEof+ throw ErrEof peek >>= \case Just '\'' | fromEnum ch > 0xFFFF -> throw ErrAstralCodePointInChar@@ -425,7 +425,7 @@ Just ch2 -> throw $ ErrLexeme (Just [ch2]) [] _ ->- throw $ ErrEof+ throw ErrEof {- stringPart@@ -570,8 +570,8 @@ Just '0' -> next *> peek >>= \case Just ch | isNumberChar ch -> throw ErrLeadingZero _ -> pure $ Just ("0", "0")- Just ch | isDigitChar ch -> Just <$> digits- _ -> pure $ Nothing+ Just ch | Char.isDigit ch -> Just <$> digits+ _ -> pure Nothing {- integer1@@ -586,10 +586,10 @@ '0' -> peek >>= \case Just ch | isNumberChar ch -> throw ErrLeadingZero _ -> pure $ Just ("0", "0")- ch | isDigitChar ch -> do+ ch | Char.isDigit ch -> do (raw, chs) <- digits pure $ Just (Text.cons ch raw, ch : chs)- _ -> pure $ Nothing+ _ -> pure Nothing {- fraction@@ -649,20 +649,20 @@ then throw ErrExpectedHex else pure $ TokInt ("0x" <> chs) $ digitsToIntegerBase 16 $ Text.unpack chs -digitsToInteger :: [Char] -> Integer+digitsToInteger :: String -> Integer digitsToInteger = digitsToIntegerBase 10 -digitsToIntegerBase :: Integer -> [Char] -> Integer-digitsToIntegerBase b = foldl' (\n c -> n * b + (toInteger (Char.digitToInt c))) 0+digitsToIntegerBase :: Integer -> String -> Integer+digitsToIntegerBase b = foldl' (\n c -> n * b + toInteger (Char.digitToInt c)) 0 -digitsToScientific :: [Char] -> [Char] -> (Integer, Int)+digitsToScientific :: String -> String -> (Integer, Int) digitsToScientific = go 0 . reverse where go !exp is [] = (digitsToInteger (reverse is), exp) go !exp is (f : fs) = go (exp - 1) (f : is) fs isSymbolChar :: Char -> Bool-isSymbolChar c = (c `elem` (":!#$%&*+./<=>?@\\^|-~" :: [Char])) || (not (Char.isAscii c) && Char.isSymbol c)+isSymbolChar c = (c `elem` (":!#$%&*+./<=>?@\\^|-~" :: String)) || (not (Char.isAscii c) && Char.isSymbol c) isReservedSymbolError :: ParserErrorType -> Bool isReservedSymbolError = (== ErrReservedSymbol)@@ -692,11 +692,8 @@ isIdentChar :: Char -> Bool isIdentChar c = Char.isAlphaNum c || c == '_' || c == '\'' -isDigitChar :: Char -> Bool-isDigitChar c = c >= '0' && c <= '9'- isNumberChar :: Char -> Bool-isNumberChar c = (c >= '0' && c <= '9') || c == '_'+isNumberChar c = Char.isDigit c || c == '_' isNormalStringChar :: Char -> Bool isNormalStringChar c = c /= '"' && c /= '\\' && c /= '\r' && c /= '\n'
src/Language/PureScript/CST/Monad.hs view
@@ -2,7 +2,7 @@ import Prelude -import Data.List (sortBy)+import Data.List (sortOn) import qualified Data.List.NonEmpty as NE import Data.Ord (comparing) import Data.Text (Text)@@ -61,12 +61,12 @@ runParser :: ParserState -> Parser a -> (ParserState, Either (NE.NonEmpty ParserError) a) runParser st (Parser k) = k st left right where- left st'@(ParserState {..}) err =+ left st'@ParserState {..} err = (st', Left $ NE.sortBy (comparing errRange) $ err NE.:| parserErrors) - right st'@(ParserState {..}) res+ right st'@ParserState {..} res | null parserErrors = (st', Right res)- | otherwise = (st', Left $ NE.fromList $ sortBy (comparing errRange) parserErrors)+ | otherwise = (st', Left $ NE.fromList $ sortOn errRange parserErrors) runTokenParser :: Parser a -> [LexResult] -> Either (NE.NonEmpty ParserError) ([ParserWarning], a) runTokenParser p buff = fmap (warnings,) res@@ -157,7 +157,7 @@ _ <- token open res <- go1 _ <- token close- pure $ res+ pure res where go1 = oneOf $ NE.fromList@@ -179,7 +179,7 @@ else parseError t' munch :: Parser SourceToken-munch = Parser $ \state@(ParserState {..}) kerr ksucc ->+munch = Parser $ \state@ParserState {..} kerr ksucc -> case parserBuff of Right tok : parserBuff' -> ksucc (state { parserBuff = parserBuff' }) tok
src/Language/PureScript/CST/Parser.y view
@@ -736,10 +736,14 @@ : ident '::' type {% checkNoWildcards $3 *> pure (Labeled $1 $2 $3) } instHead :: { InstanceHead () }- : 'instance' ident '::' constraints '=>' qualProperName manyOrEmpty(typeAtom)- { InstanceHead $1 $2 $3 (Just ($4, $5)) (getQualifiedProperName $6) $7 }+ : 'instance' constraints '=>' qualProperName manyOrEmpty(typeAtom)+ { InstanceHead $1 Nothing (Just ($2, $3)) (getQualifiedProperName $4) $5 }+ | 'instance' qualProperName manyOrEmpty(typeAtom)+ { InstanceHead $1 Nothing Nothing (getQualifiedProperName $2) $3 }+ | 'instance' ident '::' constraints '=>' qualProperName manyOrEmpty(typeAtom)+ { InstanceHead $1 (Just ($2, $3)) (Just ($4, $5)) (getQualifiedProperName $6) $7 } | 'instance' ident '::' qualProperName manyOrEmpty(typeAtom)- { InstanceHead $1 $2 $3 Nothing (getQualifiedProperName $4) $5 }+ { InstanceHead $1 (Just ($2, $3)) Nothing (getQualifiedProperName $4) $5 } constraints :: { OneOrDelimited (Constraint ()) } : constraint { One $1 }
src/Language/PureScript/CST/Positions.hs view
@@ -18,10 +18,10 @@ advanceToken pos = applyDelta pos . tokenDelta advanceLeading :: SourcePos -> [Comment LineFeed] -> SourcePos-advanceLeading pos = foldl' (\a -> applyDelta a . commentDelta lineDelta) pos+advanceLeading = foldl' $ \a -> applyDelta a . commentDelta lineDelta advanceTrailing :: SourcePos -> [Comment Void] -> SourcePos-advanceTrailing pos = foldl' (\a -> applyDelta a . commentDelta (const (0, 0))) pos+advanceTrailing = foldl' $ \a -> applyDelta a . commentDelta (const (0, 0)) tokenDelta :: Token -> (Int, Int) tokenDelta = \case@@ -118,10 +118,10 @@ labelRange a = (lblTok a, lblTok a) wrappedRange :: Wrapped a -> TokenRange-wrappedRange (Wrapped { wrpOpen, wrpClose }) = (wrpOpen, wrpClose)+wrappedRange Wrapped { wrpOpen, wrpClose } = (wrpOpen, wrpClose) moduleRange :: Module a -> TokenRange-moduleRange (Module { modKeyword, modWhere, modImports, modDecls }) =+moduleRange Module { modKeyword, modWhere, modImports, modDecls } = case (modImports, modDecls) of ([], []) -> (modKeyword, modWhere) (is, []) -> (modKeyword, snd . importDeclRange $ last is)@@ -140,7 +140,7 @@ ExportModule _ a b -> (a, nameTok b) importDeclRange :: ImportDecl a -> TokenRange-importDeclRange (ImportDecl { impKeyword, impModule, impNames, impQual })+importDeclRange ImportDecl { impKeyword, impModule, impNames, impQual } | Just (_, modName) <- impQual = (impKeyword, nameTok modName) | Just (_, imports) <- impNames = (impKeyword, wrpClose imports) | otherwise = (impKeyword, nameTok impModule)@@ -211,7 +211,7 @@ where start = instanceHeadRange hd instanceHeadRange :: InstanceHead a -> TokenRange-instanceHeadRange (InstanceHead kw _ _ _ cls types)+instanceHeadRange (InstanceHead kw _ _ cls types) | [] <- types = (kw, qualTok cls) | otherwise = (kw, snd . typeRange $ last types)
src/Language/PureScript/CST/Types.hs view
@@ -261,8 +261,7 @@ data InstanceHead a = InstanceHead { instKeyword :: SourceToken- , instName :: Name Ident- , instSep :: SourceToken+ , instNameSep :: Maybe (Name Ident, SourceToken) , instConstraints :: Maybe (OneOrDelimited (Constraint a), SourceToken) , instClass :: QualifiedName (N.ProperName 'N.ClassName) , instTypes :: [Type a]
src/Language/PureScript/CST/Utils.hs view
@@ -2,7 +2,7 @@ import Prelude -import Control.Monad (when)+import Control.Monad (unless) import Data.Coerce (coerce) import Data.Foldable (for_) import Data.Functor (($>))@@ -115,12 +115,12 @@ separated :: [(SourceToken, a)] -> Separated a separated = go [] where- go accum ((_, a) : []) = Separated a accum+ go accum [(_, a)] = Separated a accum go accum (x : xs) = go (x : accum) xs go _ [] = internalError "Separated should not be empty" consSeparated :: a -> SourceToken -> Separated a -> Separated a-consSeparated x sep (Separated {..}) = Separated x ((sep, sepHead) : sepTail)+consSeparated x sep Separated {..} = Separated x ((sep, sepHead) : sepTail) internalError :: String -> a internalError = error . ("Internal parser error: " <>)@@ -128,14 +128,14 @@ toModuleName :: SourceToken -> [Text] -> Parser (Maybe N.ModuleName) toModuleName _ [] = pure Nothing toModuleName tok ns = do- when (not (all isValidModuleNamespace ns)) $ addFailure [tok] ErrModuleName+ unless (all isValidModuleNamespace ns) $ addFailure [tok] ErrModuleName pure . Just . N.ModuleName $ Text.intercalate "." ns upperToModuleName :: SourceToken -> Parser (Name N.ModuleName) upperToModuleName tok = case tokValue tok of TokUpperName q a -> do let ns = q <> [a]- when (not (all isValidModuleNamespace ns)) $ addFailure [tok] ErrModuleName+ unless (all isValidModuleNamespace ns) $ addFailure [tok] ErrModuleName pure . Name tok . N.ModuleName $ Text.intercalate "." ns _ -> internalError $ "Invalid upper name: " <> show tok @@ -232,7 +232,7 @@ BinderConstructor a name [] NE.:| bs -> pure $ BinderConstructor a name bs a NE.:| [] -> pure a- a NE.:| _ -> unexpectedToks binderRange (unexpectedBinder) ErrExprInBinder a+ a NE.:| _ -> unexpectedToks binderRange unexpectedBinder ErrExprInBinder a toRecordFields :: Monoid a
+ src/Language/PureScript/Comments.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Defines the types of source code comments+--+module Language.PureScript.Comments where++import Prelude.Compat+import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import Data.Text (Text)+import GHC.Generics (Generic)++import Data.Aeson.TH++data Comment+ = LineComment Text+ | BlockComment Text+ deriving (Show, Eq, Ord, Generic)++instance NFData Comment+instance Serialise Comment++$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''Comment)
+ src/Language/PureScript/Constants/Prim.hs view
@@ -0,0 +1,183 @@+-- | Various constants which refer to things in Prim+module Language.PureScript.Constants.Prim where++import Prelude.Compat++import Data.String (IsString)+import Language.PureScript.Names++-- Prim values++undefined :: forall a. (IsString a) => a+undefined = "undefined"++-- Prim++partial :: forall a. (IsString a) => a+partial = "Partial"++pattern Prim :: ModuleName+pattern Prim = ModuleName "Prim"++pattern Partial :: Qualified (ProperName 'ClassName)+pattern Partial = Qualified (Just Prim) (ProperName "Partial")++pattern Record :: Qualified (ProperName 'TypeName)+pattern Record = Qualified (Just Prim) (ProperName "Record")++pattern Type :: Qualified (ProperName 'TypeName)+pattern Type = Qualified (Just Prim) (ProperName "Type")++pattern Constraint :: Qualified (ProperName 'TypeName)+pattern Constraint = Qualified (Just Prim) (ProperName "Constraint")++pattern Function :: Qualified (ProperName 'TypeName)+pattern Function = Qualified (Just Prim) (ProperName "Function")++pattern Array :: Qualified (ProperName 'TypeName)+pattern Array = Qualified (Just Prim) (ProperName "Array")++pattern Row :: Qualified (ProperName 'TypeName)+pattern Row = Qualified (Just Prim) (ProperName "Row")++-- Prim.Boolean++pattern PrimBoolean :: ModuleName+pattern PrimBoolean = ModuleName "Prim.Boolean"++booleanTrue :: Qualified (ProperName 'TypeName)+booleanTrue = Qualified (Just PrimBoolean) (ProperName "True")++booleanFalse :: Qualified (ProperName 'TypeName)+booleanFalse = Qualified (Just PrimBoolean) (ProperName "False")++-- Prim.Coerce++pattern PrimCoerce :: ModuleName+pattern PrimCoerce = ModuleName "Prim.Coerce"++pattern Coercible :: Qualified (ProperName 'ClassName)+pattern Coercible = Qualified (Just PrimCoerce) (ProperName "Coercible")++-- Prim.Ordering++pattern PrimOrdering :: ModuleName+pattern PrimOrdering = ModuleName "Prim.Ordering"++orderingLT :: Qualified (ProperName 'TypeName)+orderingLT = Qualified (Just PrimOrdering) (ProperName "LT")++orderingEQ :: Qualified (ProperName 'TypeName)+orderingEQ = Qualified (Just PrimOrdering) (ProperName "EQ")++orderingGT :: Qualified (ProperName 'TypeName)+orderingGT = Qualified (Just PrimOrdering) (ProperName "GT")++-- Prim.Row++pattern PrimRow :: ModuleName+pattern PrimRow = ModuleName "Prim.Row"++pattern RowUnion :: Qualified (ProperName 'ClassName)+pattern RowUnion = Qualified (Just PrimRow) (ProperName "Union")++pattern RowNub :: Qualified (ProperName 'ClassName)+pattern RowNub = Qualified (Just PrimRow) (ProperName "Nub")++pattern RowCons :: Qualified (ProperName 'ClassName)+pattern RowCons = Qualified (Just PrimRow) (ProperName "Cons")++pattern RowLacks :: Qualified (ProperName 'ClassName)+pattern RowLacks = Qualified (Just PrimRow) (ProperName "Lacks")++-- Prim.RowList++pattern PrimRowList :: ModuleName+pattern PrimRowList = ModuleName "Prim.RowList"++pattern RowToList :: Qualified (ProperName 'ClassName)+pattern RowToList = Qualified (Just PrimRowList) (ProperName "RowToList")++pattern RowListNil :: Qualified (ProperName 'TypeName)+pattern RowListNil = Qualified (Just PrimRowList) (ProperName "Nil")++pattern RowListCons :: Qualified (ProperName 'TypeName)+pattern RowListCons = Qualified (Just PrimRowList) (ProperName "Cons")++-- Prim.Symbol++pattern PrimSymbol :: ModuleName+pattern PrimSymbol = ModuleName "Prim.Symbol"++pattern SymbolCompare :: Qualified (ProperName 'ClassName)+pattern SymbolCompare = Qualified (Just PrimSymbol) (ProperName "Compare")++pattern SymbolAppend :: Qualified (ProperName 'ClassName)+pattern SymbolAppend = Qualified (Just PrimSymbol) (ProperName "Append")++pattern SymbolCons :: Qualified (ProperName 'ClassName)+pattern SymbolCons = Qualified (Just PrimSymbol) (ProperName "Cons")++-- Prim.TypeError++pattern PrimTypeError :: ModuleName+pattern PrimTypeError = ModuleName "Prim.TypeError"++pattern Fail :: Qualified (ProperName 'ClassName)+pattern Fail = Qualified (Just PrimTypeError) (ProperName "Fail")++pattern Warn :: Qualified (ProperName 'ClassName)+pattern Warn = Qualified (Just PrimTypeError) (ProperName "Warn")++primModules :: [ModuleName]+primModules = [Prim, PrimBoolean, PrimCoerce, PrimOrdering, PrimRow, PrimRowList, PrimSymbol, PrimTypeError]++typ :: forall a. (IsString a) => a+typ = "Type"++kindBoolean :: forall a. (IsString a) => a+kindBoolean = "Boolean"++kindOrdering :: forall a. (IsString a) => a+kindOrdering = "Ordering"++kindRowList :: forall a. (IsString a) => a+kindRowList = "RowList"++symbol :: forall a. (IsString a) => a+symbol = "Symbol"++doc :: forall a. (IsString a) => a+doc = "Doc"++row :: forall a. (IsString a) => a+row = "Row"++constraint :: forall a. (IsString a) => a+constraint = "Constraint"++-- Modules++prim :: forall a. (IsString a) => a+prim = "Prim"++moduleBoolean :: forall a. (IsString a) => a+moduleBoolean = "Boolean"++moduleCoerce :: forall a. (IsString a) => a+moduleCoerce = "Coerce"++moduleOrdering :: forall a. (IsString a) => a+moduleOrdering = "Ordering"++moduleRow :: forall a. (IsString a) => a+moduleRow = "Row"++moduleRowList :: forall a. (IsString a) => a+moduleRowList = "RowList"++moduleSymbol :: forall a. (IsString a) => a+moduleSymbol = "Symbol"++typeError :: forall a. (IsString a) => a+typeError = "TypeError"
+ src/Language/PureScript/Crash.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE CPP #-}++module Language.PureScript.Crash where++import Prelude.Compat++import qualified GHC.Stack++-- | A compatibility wrapper for the @GHC.Stack.HasCallStack@ constraint.+#if __GLASGOW_HASKELL__ >= 800+type HasCallStack = GHC.Stack.HasCallStack+#elif MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)+type HasCallStack = (?callStack :: GHC.Stack.CallStack)+#else+import GHC.Exts (Constraint)+-- CallStack wasn't present in GHC 7.10.1+type HasCallStack = (() :: Constraint)+#endif++-- | Exit with an error message and a crash report link.+internalError :: HasCallStack => String -> a+internalError =+ error+ . ("An internal error occurred during compilation: " ++)+ . (++ "\nPlease report this at https://github.com/purescript/purescript/issues")
+ src/Language/PureScript/Environment.hs view
@@ -0,0 +1,630 @@+module Language.PureScript.Environment where++import Prelude.Compat+import Protolude (ordNub)++import GHC.Generics (Generic)+import Control.DeepSeq (NFData)+import Codec.Serialise (Serialise)+import Data.Aeson ((.=), (.:))+import qualified Data.Aeson as A+import qualified Data.Map as M+import qualified Data.Set as S+import Data.Maybe (fromMaybe, mapMaybe)+import Data.Text (Text)+import qualified Data.Text as T+import Data.Tree (Tree, rootLabel)+import qualified Data.Graph as G+import Data.Foldable (toList)+import qualified Data.List.NonEmpty as NEL++import Language.PureScript.AST.SourcePos+import Language.PureScript.Crash+import Language.PureScript.Names+import Language.PureScript.Roles+import Language.PureScript.TypeClassDictionaries+import Language.PureScript.Types+import qualified Language.PureScript.Constants.Prim as C++-- | The @Environment@ defines all values and types which are currently in scope:+data Environment = Environment+ { names :: M.Map (Qualified Ident) (SourceType, NameKind, NameVisibility)+ -- ^ Values currently in scope+ , types :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+ -- ^ Type names currently in scope+ , dataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) (DataDeclType, ProperName 'TypeName, SourceType, [Ident])+ -- ^ Data constructors currently in scope, along with their associated type+ -- constructor name, argument types and return type.+ , roleDeclarations :: M.Map (Qualified (ProperName 'TypeName)) [Role]+ -- ^ Explicit role declarations currently in scope. Note that this field is+ -- only used to store declared roles temporarily until they can be checked;+ -- to find a type's real checked and/or inferred roles, refer to the TypeKind+ -- in the `types` field.+ , typeSynonyms :: M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe SourceType)], SourceType)+ -- ^ Type synonyms currently in scope+ , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) (NEL.NonEmpty NamedDict)))+ -- ^ Available type class dictionaries. When looking up 'Nothing' in the+ -- outer map, this returns the map of type class dictionaries in local+ -- scope (ie dictionaries brought in by a constrained type).+ , typeClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+ -- ^ Type classes+ } deriving (Show, Generic)++instance NFData Environment++-- | Information about a type class+data TypeClassData = TypeClassData+ { typeClassArguments :: [(Text, Maybe SourceType)]+ -- ^ A list of type argument names, and their kinds, where kind annotations+ -- were provided.+ , typeClassMembers :: [(Ident, SourceType)]+ -- ^ A list of type class members and their types. Type arguments listed above+ -- are considered bound in these types.+ , typeClassSuperclasses :: [SourceConstraint]+ -- ^ A list of superclasses of this type class. Type arguments listed above+ -- are considered bound in the types appearing in these constraints.+ , typeClassDependencies :: [FunctionalDependency]+ -- ^ A list of functional dependencies for the type arguments of this class.+ , typeClassDeterminedArguments :: S.Set Int+ -- ^ A set of indexes of type argument that are fully determined by other+ -- arguments via functional dependencies. This can be computed from both+ -- typeClassArguments and typeClassDependencies.+ , typeClassCoveringSets :: S.Set (S.Set Int)+ -- ^ A sets of arguments that can be used to infer all other arguments.+ , typeClassIsEmpty :: Bool+ -- ^ Whether or not dictionaries for this type class are necessarily empty.+ } deriving (Show, Generic)++instance NFData TypeClassData++-- | A functional dependency indicates a relationship between two sets of+-- type arguments in a class declaration.+data FunctionalDependency = FunctionalDependency+ { fdDeterminers :: [Int]+ -- ^ the type arguments which determine the determined type arguments+ , fdDetermined :: [Int]+ -- ^ the determined type arguments+ } deriving (Show, Generic)++instance NFData FunctionalDependency+instance Serialise FunctionalDependency++instance A.FromJSON FunctionalDependency where+ parseJSON = A.withObject "FunctionalDependency" $ \o ->+ FunctionalDependency+ <$> o .: "determiners"+ <*> o .: "determined"++instance A.ToJSON FunctionalDependency where+ toJSON FunctionalDependency{..} =+ A.object [ "determiners" .= fdDeterminers+ , "determined" .= fdDetermined+ ]++-- | The initial environment with no values and only the default javascript types defined+initEnvironment :: Environment+initEnvironment = Environment M.empty allPrimTypes M.empty M.empty M.empty M.empty allPrimClasses++-- | A constructor for TypeClassData that computes which type class arguments are fully determined+-- and argument covering sets.+-- Fully determined means that this argument cannot be used when selecting a type class instance.+-- A covering set is a minimal collection of arguments that can be used to find an instance and+-- therefore determine all other type arguments.+--+-- An example of the difference between determined and fully determined would be with the class:+-- ```class C a b c | a -> b, b -> a, b -> c```+-- In this case, `a` must differ when `b` differs, and vice versa - each is determined by the other.+-- Both `a` and `b` can be used in selecting a type class instance. However, `c` cannot - it is+-- fully determined by `a` and `b`.+--+-- Define a graph of type class arguments with edges being fundep determiners to determined. Each+-- argument also has a self looping edge.+-- An argument is fully determined if doesn't appear at the start of a path of strongly connected components.+-- An argument is not fully determined otherwise.+--+-- The way we compute this is by saying: an argument X is fully determined if there are arguments that+-- determine X that X does not determine. This is the same thing: everything X determines includes everything+-- in its SCC, and everything determining X is either before it in an SCC path, or in the same SCC.+makeTypeClassData+ :: [(Text, Maybe SourceType)]+ -> [(Ident, SourceType)]+ -> [SourceConstraint]+ -> [FunctionalDependency]+ -> Bool+ -> TypeClassData+makeTypeClassData args m s deps = TypeClassData args m s deps determinedArgs coveringSets+ where+ argumentIndices = [0 .. length args - 1]++ -- each argument determines themselves+ identities = (\i -> (i, [i])) <$> argumentIndices++ -- list all the edges in the graph: for each fundep an edge exists for each determiner to each determined+ contributingDeps = M.fromListWith (++) $ identities ++ do+ fd <- deps+ src <- fdDeterminers fd+ (src, fdDetermined fd) : map (, []) (fdDetermined fd)++ -- build a graph of which arguments determine other arguments+ (depGraph, fromVertex, fromKey) = G.graphFromEdges ((\(n, v) -> (n, n, ordNub v)) <$> M.toList contributingDeps)++ -- do there exist any arguments that contribute to `arg` that `arg` doesn't contribute to+ isFunDepDetermined :: Int -> Bool+ isFunDepDetermined arg = case fromKey arg of+ Nothing -> internalError "Unknown argument index in makeTypeClassData"+ Just v -> let contributesToVar = G.reachable (G.transposeG depGraph) v+ varContributesTo = G.reachable depGraph v+ in any (`notElem` varContributesTo) contributesToVar++ -- find all the arguments that are determined+ determinedArgs :: S.Set Int+ determinedArgs = S.fromList $ filter isFunDepDetermined argumentIndices++ argFromVertex :: G.Vertex -> Int+ argFromVertex index = let (_, arg, _) = fromVertex index in arg++ isVertexDetermined :: G.Vertex -> Bool+ isVertexDetermined = isFunDepDetermined . argFromVertex++ -- from an scc find the non-determined args+ sccNonDetermined :: Tree G.Vertex -> Maybe [Int]+ sccNonDetermined tree+ -- if any arg in an scc is determined then all of them are+ | isVertexDetermined (rootLabel tree) = Nothing+ | otherwise = Just (argFromVertex <$> toList tree)++ -- find the covering sets+ coveringSets :: S.Set (S.Set Int)+ coveringSets = let funDepSets = sequence (mapMaybe sccNonDetermined (G.scc depGraph))+ in S.fromList (S.fromList <$> funDepSets)++-- | The visibility of a name in scope+data NameVisibility+ = Undefined+ -- ^ The name is defined in the current binding group, but is not visible+ | Defined+ -- ^ The name is defined in the another binding group, or has been made visible by a function binder+ deriving (Show, Eq, Generic)++instance NFData NameVisibility+instance Serialise NameVisibility++-- | A flag for whether a name is for an private or public value - only public values will be+-- included in a generated externs file.+data NameKind+ = Private+ -- ^ A private value introduced as an artifact of code generation (class instances, class member+ -- accessors, etc.)+ | Public+ -- ^ A public value for a module member or foreign import declaration+ | External+ -- ^ A name for member introduced by foreign import+ deriving (Show, Eq, Generic)++instance NFData NameKind+instance Serialise NameKind++-- | The kinds of a type+data TypeKind+ = DataType DataDeclType [(Text, Maybe SourceType, Role)] [(ProperName 'ConstructorName, [SourceType])]+ -- ^ Data type+ | TypeSynonym+ -- ^ Type synonym+ | ExternData [Role]+ -- ^ Foreign data+ | LocalTypeVariable+ -- ^ A local type variable+ | ScopedTypeVar+ -- ^ A scoped type variable+ deriving (Show, Eq, Generic)++instance NFData TypeKind+instance Serialise TypeKind++-- | The type ('data' or 'newtype') of a data type declaration+data DataDeclType+ = Data+ -- ^ A standard data constructor+ | Newtype+ -- ^ A newtype constructor+ deriving (Show, Eq, Ord, Generic)++instance NFData DataDeclType+instance Serialise DataDeclType++showDataDeclType :: DataDeclType -> Text+showDataDeclType Data = "data"+showDataDeclType Newtype = "newtype"++instance A.ToJSON DataDeclType where+ toJSON = A.toJSON . showDataDeclType++instance A.FromJSON DataDeclType where+ parseJSON = A.withText "DataDeclType" $ \case+ "data" -> return Data+ "newtype" -> return Newtype+ other -> fail $ "invalid type: '" ++ T.unpack other ++ "'"++-- | Construct a ProperName in the Prim module+primName :: Text -> Qualified (ProperName a)+primName = Qualified (Just C.Prim) . ProperName++-- | Construct a 'ProperName' in the @Prim.NAME@ module.+primSubName :: Text -> Text -> Qualified (ProperName a)+primSubName sub =+ Qualified (Just $ ModuleName $ C.prim <> "." <> sub) . ProperName++primKind :: Text -> SourceType+primKind = primTy++primSubKind :: Text -> Text -> SourceType+primSubKind sub = TypeConstructor nullSourceAnn . primSubName sub++-- | Kind of ground types+kindType :: SourceType+kindType = primKind C.typ++kindConstraint :: SourceType+kindConstraint = primKind C.constraint++isKindType :: Type a -> Bool+isKindType (TypeConstructor _ n) = n == primName C.typ+isKindType _ = False++kindSymbol :: SourceType+kindSymbol = primKind C.symbol++kindDoc :: SourceType+kindDoc = primSubKind C.typeError C.doc++kindBoolean :: SourceType+kindBoolean = primSubKind C.moduleBoolean C.kindBoolean++kindOrdering :: SourceType+kindOrdering = primSubKind C.moduleOrdering C.kindOrdering++kindRowList :: SourceType -> SourceType+kindRowList = TypeApp nullSourceAnn (primSubKind C.moduleRowList C.kindRowList)++kindRow :: SourceType -> SourceType+kindRow = TypeApp nullSourceAnn (primKind C.row)++kindOfREmpty :: SourceType+kindOfREmpty = tyForall "k" kindType (kindRow (tyVar "k"))++-- | Construct a type in the Prim module+primTy :: Text -> SourceType+primTy = TypeConstructor nullSourceAnn . primName++-- | Type constructor for functions+tyFunction :: SourceType+tyFunction = primTy "Function"++-- | Type constructor for strings+tyString :: SourceType+tyString = primTy "String"++-- | Type constructor for strings+tyChar :: SourceType+tyChar = primTy "Char"++-- | Type constructor for numbers+tyNumber :: SourceType+tyNumber = primTy "Number"++-- | Type constructor for integers+tyInt :: SourceType+tyInt = primTy "Int"++-- | Type constructor for booleans+tyBoolean :: SourceType+tyBoolean = primTy "Boolean"++-- | Type constructor for arrays+tyArray :: SourceType+tyArray = primTy "Array"++-- | Type constructor for records+tyRecord :: SourceType+tyRecord = primTy "Record"++tyVar :: Text -> SourceType+tyVar = TypeVar nullSourceAnn++tyForall :: Text -> SourceType -> SourceType -> SourceType+tyForall var k ty = ForAll nullSourceAnn var (Just k) ty Nothing++-- | Check whether a type is a record+isObject :: Type a -> Bool+isObject = isTypeOrApplied tyRecord++-- | Check whether a type is a function+isFunction :: Type a -> Bool+isFunction = isTypeOrApplied tyFunction++isTypeOrApplied :: Type a -> Type b -> Bool+isTypeOrApplied t1 (TypeApp _ t2 _) = eqType t1 t2+isTypeOrApplied t1 t2 = eqType t1 t2++-- | Smart constructor for function types+function :: SourceType -> SourceType -> SourceType+function = TypeApp nullSourceAnn . TypeApp nullSourceAnn tyFunction++-- To make reading the kind signatures below easier+(-:>) :: SourceType -> SourceType -> SourceType+(-:>) = function+infixr 4 -:>++primClass :: Qualified (ProperName 'TypeName) -> (SourceType -> SourceType) -> [(Qualified (ProperName 'TypeName), (SourceType, TypeKind))]+primClass name mkKind =+ [ let k = mkKind kindConstraint+ in (name, (k, ExternData (nominalRolesForKind k)))+ , let k = mkKind kindType+ in (dictSynonymName <$> name, (k, TypeSynonym))+ ]++-- | The primitive types in the external environment with their+-- associated kinds. There are also pseudo `Fail`, `Warn`, and `Partial` types+-- that correspond to the classes with the same names.+primTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primTypes =+ M.fromList+ [ (primName "Type", (kindType, ExternData []))+ , (primName "Constraint", (kindType, ExternData []))+ , (primName "Symbol", (kindType, ExternData []))+ , (primName "Row", (kindType -:> kindType, ExternData [Phantom]))+ , (primName "Function", (kindType -:> kindType -:> kindType, ExternData [Representational, Representational]))+ , (primName "Array", (kindType -:> kindType, ExternData [Representational]))+ , (primName "Record", (kindRow kindType -:> kindType, ExternData [Representational]))+ , (primName "String", (kindType, ExternData []))+ , (primName "Char", (kindType, ExternData []))+ , (primName "Number", (kindType, ExternData []))+ , (primName "Int", (kindType, ExternData []))+ , (primName "Boolean", (kindType, ExternData []))+ , (primName "Partial", (kindConstraint, ExternData []))+ ]++-- | This 'Map' contains all of the prim types from all Prim modules.+allPrimTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+allPrimTypes = M.unions+ [ primTypes+ , primBooleanTypes+ , primCoerceTypes+ , primOrderingTypes+ , primRowTypes+ , primRowListTypes+ , primSymbolTypes+ , primTypeErrorTypes+ ]++primBooleanTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primBooleanTypes =+ M.fromList+ [ (primSubName C.moduleBoolean "True", (tyBoolean, ExternData []))+ , (primSubName C.moduleBoolean "False", (tyBoolean, ExternData []))+ ]++primCoerceTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primCoerceTypes =+ M.fromList $ mconcat+ [ primClass (primSubName C.moduleCoerce "Coercible") (\kind -> tyForall "k" kindType $ tyVar "k" -:> tyVar "k" -:> kind)+ ]++primOrderingTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primOrderingTypes =+ M.fromList+ [ (primSubName C.moduleOrdering "Ordering", (kindType, ExternData []))+ , (primSubName C.moduleOrdering "LT", (kindOrdering, ExternData []))+ , (primSubName C.moduleOrdering "EQ", (kindOrdering, ExternData []))+ , (primSubName C.moduleOrdering "GT", (kindOrdering, ExternData []))+ ]++primRowTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primRowTypes =+ M.fromList $ mconcat+ [ primClass (primSubName C.moduleRow "Union") (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)+ , primClass (primSubName C.moduleRow "Nub") (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)+ , primClass (primSubName C.moduleRow "Lacks") (\kind -> tyForall "k" kindType $ kindSymbol -:> kindRow (tyVar "k") -:> kind)+ , primClass (primSubName C.moduleRow "Cons") (\kind -> tyForall "k" kindType $ kindSymbol -:> tyVar "k" -:> kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)+ ]++primRowListTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primRowListTypes =+ M.fromList $+ [ (primSubName C.moduleRowList "RowList", (kindType -:> kindType, ExternData [Phantom]))+ , (primSubName C.moduleRowList "Cons", (tyForall "k" kindType $ kindSymbol -:> tyVar "k" -:> kindRowList (tyVar "k") -:> kindRowList (tyVar "k"), ExternData [Phantom, Phantom, Phantom]))+ , (primSubName C.moduleRowList "Nil", (tyForall "k" kindType $ kindRowList (tyVar "k"), ExternData []))+ ] <> mconcat+ [ primClass (primSubName C.moduleRowList "RowToList") (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRowList (tyVar "k") -:> kind)+ ]++primSymbolTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primSymbolTypes =+ M.fromList $ mconcat+ [ primClass (primSubName C.moduleSymbol "Append") (\kind -> kindSymbol -:> kindSymbol -:> kindSymbol -:> kind)+ , primClass (primSubName C.moduleSymbol "Compare") (\kind -> kindSymbol -:> kindSymbol -:> kindOrdering -:> kind)+ , primClass (primSubName C.moduleSymbol "Cons") (\kind -> kindSymbol -:> kindSymbol -:> kindSymbol -:> kind)+ ]++primTypeErrorTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)+primTypeErrorTypes =+ M.fromList $+ [ (primSubName C.typeError "Doc", (kindType, ExternData []))+ , (primSubName C.typeError "Fail", (kindDoc -:> kindConstraint, ExternData [Nominal]))+ , (primSubName C.typeError "Warn", (kindDoc -:> kindConstraint, ExternData [Nominal]))+ , (primSubName C.typeError "Text", (kindSymbol -:> kindDoc, ExternData [Phantom]))+ , (primSubName C.typeError "Quote", (kindType -:> kindDoc, ExternData [Phantom]))+ , (primSubName C.typeError "QuoteLabel", (kindSymbol -:> kindDoc, ExternData [Phantom]))+ , (primSubName C.typeError "Beside", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))+ , (primSubName C.typeError "Above", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))+ ] <> mconcat+ [ primClass (primSubName C.typeError "Fail") (\kind -> kindDoc -:> kind)+ , primClass (primSubName C.typeError "Warn") (\kind -> kindDoc -:> kind)+ ]++-- | The primitive class map. This just contains the `Partial` class.+-- `Partial` is used as a kind of magic constraint for partial functions.+primClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primClasses =+ M.fromList+ [ (primName "Partial", makeTypeClassData [] [] [] [] True)+ ]++-- | This contains all of the type classes from all Prim modules.+allPrimClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+allPrimClasses = M.unions+ [ primClasses+ , primCoerceClasses+ , primRowClasses+ , primRowListClasses+ , primSymbolClasses+ , primTypeErrorClasses+ ]++primCoerceClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primCoerceClasses =+ M.fromList+ -- class Coercible (a :: k) (b :: k)+ [ (primSubName C.moduleCoerce "Coercible", makeTypeClassData+ [ ("a", Just (tyVar "k"))+ , ("b", Just (tyVar "k"))+ ] [] [] [] True)+ ]++primRowClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primRowClasses =+ M.fromList+ -- class Union (left :: Row k) (right :: Row k) (union :: Row k) | left right -> union, right union -> left, union left -> right+ [ (primSubName C.moduleRow "Union", makeTypeClassData+ [ ("left", Just (kindRow (tyVar "k")))+ , ("right", Just (kindRow (tyVar "k")))+ , ("union", Just (kindRow (tyVar "k")))+ ] [] []+ [ FunctionalDependency [0, 1] [2]+ , FunctionalDependency [1, 2] [0]+ , FunctionalDependency [2, 0] [1]+ ] True)++ -- class Nub (original :: Row k) (nubbed :: Row k) | original -> nubbed+ , (primSubName C.moduleRow "Nub", makeTypeClassData+ [ ("original", Just (kindRow (tyVar "k")))+ , ("nubbed", Just (kindRow (tyVar "k")))+ ] [] []+ [ FunctionalDependency [0] [1]+ ] True)++ -- class Lacks (label :: Symbol) (row :: Row k)+ , (primSubName C.moduleRow "Lacks", makeTypeClassData+ [ ("label", Just kindSymbol)+ , ("row", Just (kindRow (tyVar "k")))+ ] [] [] [] True)++ -- class RowCons (label :: Symbol) (a :: k) (tail :: Row k) (row :: Row k) | label tail a -> row, label row -> tail a+ , (primSubName C.moduleRow "Cons", makeTypeClassData+ [ ("label", Just kindSymbol)+ , ("a", Just (tyVar "k"))+ , ("tail", Just (kindRow (tyVar "k")))+ , ("row", Just (kindRow (tyVar "k")))+ ] [] []+ [ FunctionalDependency [0, 1, 2] [3]+ , FunctionalDependency [0, 3] [1, 2]+ ] True)+ ]++primRowListClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primRowListClasses =+ M.fromList+ -- class RowToList (row :: Row k) (list :: RowList k) | row -> list+ [ (primSubName C.moduleRowList "RowToList", makeTypeClassData+ [ ("row", Just (kindRow (tyVar "k")))+ , ("list", Just (kindRowList (tyVar "k")))+ ] [] []+ [ FunctionalDependency [0] [1]+ ] True)+ ]++primSymbolClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primSymbolClasses =+ M.fromList+ -- class Append (left :: Symbol) (right :: Symbol) (appended :: Symbol) | left right -> appended, right appended -> left, appended left -> right+ [ (primSubName C.moduleSymbol "Append", makeTypeClassData+ [ ("left", Just kindSymbol)+ , ("right", Just kindSymbol)+ , ("appended", Just kindSymbol)+ ] [] []+ [ FunctionalDependency [0, 1] [2]+ , FunctionalDependency [1, 2] [0]+ , FunctionalDependency [2, 0] [1]+ ] True)++ -- class Compare (left :: Symbol) (right :: Symbol) (ordering :: Ordering) | left right -> ordering+ , (primSubName C.moduleSymbol "Compare", makeTypeClassData+ [ ("left", Just kindSymbol)+ , ("right", Just kindSymbol)+ , ("ordering", Just kindOrdering)+ ] [] []+ [ FunctionalDependency [0, 1] [2]+ ] True)++ -- class Cons (head :: Symbol) (tail :: Symbol) (symbol :: Symbol) | head tail -> symbol, symbol -> head tail+ , (primSubName C.moduleSymbol "Cons", makeTypeClassData+ [ ("head", Just kindSymbol)+ , ("tail", Just kindSymbol)+ , ("symbol", Just kindSymbol)+ ] [] []+ [ FunctionalDependency [0, 1] [2]+ , FunctionalDependency [2] [0, 1]+ ] True)+ ]++primTypeErrorClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData+primTypeErrorClasses =+ M.fromList+ -- class Fail (message :: Symbol)+ [ (primSubName C.typeError "Fail", makeTypeClassData+ [("message", Just kindDoc)] [] [] [] True)++ -- class Warn (message :: Symbol)+ , (primSubName C.typeError "Warn", makeTypeClassData+ [("message", Just kindDoc)] [] [] [] True)+ ]++-- | Finds information about data constructors from the current environment.+lookupConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> (DataDeclType, ProperName 'TypeName, SourceType, [Ident])+lookupConstructor env ctor =+ fromMaybe (internalError "Data constructor not found") $ ctor `M.lookup` dataConstructors env++-- | Checks whether a data constructor is for a newtype.+isNewtypeConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> Bool+isNewtypeConstructor e ctor = case lookupConstructor e ctor of+ (Newtype, _, _, _) -> True+ (Data, _, _, _) -> False++-- | Finds information about values from the current environment.+lookupValue :: Environment -> Qualified Ident -> Maybe (SourceType, NameKind, NameVisibility)+lookupValue env ident = ident `M.lookup` names env++dictSynonymName' :: Text -> Text+dictSynonymName' = (<> "$Dict")++dictSynonymName :: ProperName a -> ProperName a+dictSynonymName = ProperName . dictSynonymName' . runProperName++isDictSynonym :: ProperName a -> Bool+isDictSynonym = T.isSuffixOf "$Dict" . runProperName++-- |+-- Given the kind of a type, generate a list @Nominal@ roles. This is used for+-- opaque foreign types as well as type classes.+nominalRolesForKind :: Type a -> [Role]+nominalRolesForKind k = replicate (kindArity k) Nominal++kindArity :: Type a -> Int+kindArity = length . fst . unapplyKinds++unapplyKinds :: Type a -> ([Type a], Type a)+unapplyKinds = go [] where+ go kinds (TypeApp _ (TypeApp _ fn k1) k2)+ | eqType fn tyFunction = go (k1 : kinds) k2+ go kinds (ForAll _ _ _ k _) = go kinds k+ go kinds k = (reverse kinds, k)
+ src/Language/PureScript/Label.hs view
@@ -0,0 +1,21 @@+module Language.PureScript.Label (Label(..)) where++import Prelude.Compat hiding (lex)+import GHC.Generics (Generic)+import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import Data.Monoid ()+import Data.String (IsString(..))+import qualified Data.Aeson as A++import Language.PureScript.PSString (PSString)++-- |+-- Labels are used as record keys and row entry names. Labels newtype PSString+-- because records are indexable by PureScript strings at runtime.+--+newtype Label = Label { runLabel :: PSString }+ deriving (Show, Eq, Ord, IsString, Semigroup, Monoid, A.ToJSON, A.FromJSON, Generic)++instance NFData Label+instance Serialise Label
+ src/Language/PureScript/Names.hs view
@@ -0,0 +1,255 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Data types for names+--+module Language.PureScript.Names where++import Prelude.Compat++import Codec.Serialise (Serialise)+import Control.Monad.Supply.Class+import Control.DeepSeq (NFData)+import Data.Functor.Contravariant (contramap)+import qualified Data.Vector as V++import GHC.Generics (Generic)+import Data.Aeson+import Data.Aeson.TH+import Data.Text (Text)+import qualified Data.Text as T++-- | A sum of the possible name types, useful for error and lint messages.+data Name+ = IdentName Ident+ | ValOpName (OpName 'ValueOpName)+ | TyName (ProperName 'TypeName)+ | TyOpName (OpName 'TypeOpName)+ | DctorName (ProperName 'ConstructorName)+ | TyClassName (ProperName 'ClassName)+ | ModName ModuleName+ deriving (Eq, Ord, Show, Generic)++instance NFData Name+instance Serialise Name++getIdentName :: Name -> Maybe Ident+getIdentName (IdentName name) = Just name+getIdentName _ = Nothing++getValOpName :: Name -> Maybe (OpName 'ValueOpName)+getValOpName (ValOpName name) = Just name+getValOpName _ = Nothing++getTypeName :: Name -> Maybe (ProperName 'TypeName)+getTypeName (TyName name) = Just name+getTypeName _ = Nothing++getTypeOpName :: Name -> Maybe (OpName 'TypeOpName)+getTypeOpName (TyOpName name) = Just name+getTypeOpName _ = Nothing++getDctorName :: Name -> Maybe (ProperName 'ConstructorName)+getDctorName (DctorName name) = Just name+getDctorName _ = Nothing++getClassName :: Name -> Maybe (ProperName 'ClassName)+getClassName (TyClassName name) = Just name+getClassName _ = Nothing++getModName :: Name -> Maybe ModuleName+getModName (ModName name) = Just name+getModName _ = Nothing++-- |+-- Names for value identifiers+--+data Ident+ -- |+ -- An alphanumeric identifier+ --+ = Ident Text+ -- |+ -- A generated name for an identifier+ --+ | GenIdent (Maybe Text) Integer+ -- |+ -- A generated name used only for type-checking+ --+ | UnusedIdent+ deriving (Show, Eq, Ord, Generic)++instance NFData Ident+instance Serialise Ident++runIdent :: Ident -> Text+runIdent (Ident i) = i+runIdent (GenIdent Nothing n) = "$" <> T.pack (show n)+runIdent (GenIdent (Just name) n) = "$" <> name <> T.pack (show n)+runIdent UnusedIdent = "$__unused"++showIdent :: Ident -> Text+showIdent = runIdent++freshIdent :: MonadSupply m => Text -> m Ident+freshIdent name = GenIdent (Just name) <$> fresh++freshIdent' :: MonadSupply m => m Ident+freshIdent' = GenIdent Nothing <$> fresh++-- |+-- Operator alias names.+--+newtype OpName (a :: OpNameType) = OpName { runOpName :: Text }+ deriving (Show, Eq, Ord, Generic)++instance NFData (OpName a)+instance Serialise (OpName a)++instance ToJSON (OpName a) where+ toJSON = toJSON . runOpName++instance FromJSON (OpName a) where+ parseJSON = fmap OpName . parseJSON++showOp :: OpName a -> Text+showOp op = "(" <> runOpName op <> ")"++-- |+-- The closed set of operator alias types.+--+data OpNameType = ValueOpName | TypeOpName | AnyOpName++eraseOpName :: OpName a -> OpName 'AnyOpName+eraseOpName = OpName . runOpName++coerceOpName :: OpName a -> OpName b+coerceOpName = OpName . runOpName++-- |+-- Proper names, i.e. capitalized names for e.g. module names, type//data constructors.+--+newtype ProperName (a :: ProperNameType) = ProperName { runProperName :: Text }+ deriving (Show, Eq, Ord, Generic)++instance NFData (ProperName a)+instance Serialise (ProperName a)++instance ToJSON (ProperName a) where+ toJSON = toJSON . runProperName++instance FromJSON (ProperName a) where+ parseJSON = fmap ProperName . parseJSON++-- |+-- The closed set of proper name types.+--+data ProperNameType+ = TypeName+ | ConstructorName+ | ClassName+ | Namespace++-- |+-- Coerces a ProperName from one ProperNameType to another. This should be used+-- with care, and is primarily used to convert ClassNames into TypeNames after+-- classes have been desugared.+--+coerceProperName :: ProperName a -> ProperName b+coerceProperName = ProperName . runProperName++-- |+-- Module names+--+newtype ModuleName = ModuleName Text+ deriving (Show, Eq, Ord, Generic)+ deriving newtype Serialise++instance NFData ModuleName++runModuleName :: ModuleName -> Text+runModuleName (ModuleName name) = name++moduleNameFromString :: Text -> ModuleName+moduleNameFromString = ModuleName++isBuiltinModuleName :: ModuleName -> Bool+isBuiltinModuleName (ModuleName mn) = mn == "Prim" || "Prim." `T.isPrefixOf` mn++-- |+-- A qualified name, i.e. a name with an optional module name+--+data Qualified a = Qualified (Maybe ModuleName) a+ deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic)++instance NFData a => NFData (Qualified a)+instance Serialise a => Serialise (Qualified a)++showQualified :: (a -> Text) -> Qualified a -> Text+showQualified f (Qualified Nothing a) = f a+showQualified f (Qualified (Just name) a) = runModuleName name <> "." <> f a++getQual :: Qualified a -> Maybe ModuleName+getQual (Qualified mn _) = mn++-- |+-- Provide a default module name, if a name is unqualified+--+qualify :: ModuleName -> Qualified a -> (ModuleName, a)+qualify m (Qualified Nothing a) = (m, a)+qualify _ (Qualified (Just m) a) = (m, a)++-- |+-- Makes a qualified value from a name and module name.+--+mkQualified :: a -> ModuleName -> Qualified a+mkQualified name mn = Qualified (Just mn) name++-- | Remove the module name from a qualified name+disqualify :: Qualified a -> a+disqualify (Qualified _ a) = a++-- |+-- Remove the qualification from a value when it is qualified with a particular+-- module name.+--+disqualifyFor :: Maybe ModuleName -> Qualified a -> Maybe a+disqualifyFor mn (Qualified mn' a) | mn == mn' = Just a+disqualifyFor _ _ = Nothing++-- |+-- Checks whether a qualified value is actually qualified with a module reference+--+isQualified :: Qualified a -> Bool+isQualified (Qualified Nothing _) = False+isQualified _ = True++-- |+-- Checks whether a qualified value is not actually qualified with a module reference+--+isUnqualified :: Qualified a -> Bool+isUnqualified = not . isQualified++-- |+-- Checks whether a qualified value is qualified with a particular module+--+isQualifiedWith :: ModuleName -> Qualified a -> Bool+isQualifiedWith mn (Qualified (Just mn') _) = mn == mn'+isQualifiedWith _ _ = False++$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''Qualified)+$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''Ident)++instance ToJSON ModuleName where+ toJSON (ModuleName name) = toJSON (T.splitOn "." name)++instance FromJSON ModuleName where+ parseJSON = withArray "ModuleName" $ \names -> do+ names' <- traverse parseJSON names+ pure (ModuleName (T.intercalate "." (V.toList names')))++instance ToJSONKey ModuleName where+ toJSONKey = contramap runModuleName toJSONKey++instance FromJSONKey ModuleName where+ fromJSONKey = fmap moduleNameFromString fromJSONKey
+ src/Language/PureScript/PSString.hs view
@@ -0,0 +1,239 @@+module Language.PureScript.PSString+ ( PSString+ , toUTF16CodeUnits+ , decodeString+ , decodeStringEither+ , decodeStringWithReplacement+ , prettyPrintString+ , prettyPrintStringJS+ , mkString+ ) where++import Prelude.Compat+import GHC.Generics (Generic)+import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import Control.Exception (try, evaluate)+import Control.Applicative ((<|>))+import qualified Data.Char as Char+import Data.Bits (shiftR)+import Data.List (unfoldr)+import Data.Scientific (toBoundedInteger)+import Data.String (IsString(..))+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.Text (Text)+import qualified Data.Text as T+import Data.Text.Encoding (decodeUtf16BE)+import Data.Text.Encoding.Error (UnicodeException)+import qualified Data.Vector as V+import Data.Word (Word16, Word8)+import Numeric (showHex)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Aeson as A+import qualified Data.Aeson.Types as A++-- |+-- Strings in PureScript are sequences of UTF-16 code units, which do not+-- necessarily represent UTF-16 encoded text. For example, it is permissible+-- for a string to contain *lone surrogates,* i.e. characters in the range+-- U+D800 to U+DFFF which do not appear as a part of a surrogate pair.+--+-- The Show instance for PSString produces a string literal which would+-- represent the same data were it inserted into a PureScript source file.+--+-- Because JSON parsers vary wildly in terms of how they deal with lone+-- surrogates in JSON strings, the ToJSON instance for PSString produces JSON+-- strings where that would be safe (i.e. when there are no lone surrogates),+-- and arrays of UTF-16 code units (integers) otherwise.+--+newtype PSString = PSString { toUTF16CodeUnits :: [Word16] }+ deriving (Eq, Ord, Semigroup, Monoid, Generic)++instance NFData PSString+instance Serialise PSString++instance Show PSString where+ show = show . codePoints++-- |+-- Decode a PSString to a String, representing any lone surrogates as the+-- reserved code point with that index. Warning: if there are any lone+-- surrogates, converting the result to Text via Data.Text.pack will result in+-- loss of information as those lone surrogates will be replaced with U+FFFD+-- REPLACEMENT CHARACTER. Because this function requires care to use correctly,+-- we do not export it.+--+codePoints :: PSString -> String+codePoints = map (either (Char.chr . fromIntegral) id) . decodeStringEither++-- |+-- Decode a PSString as UTF-16 text. Lone surrogates will be replaced with+-- U+FFFD REPLACEMENT CHARACTER+--+decodeStringWithReplacement :: PSString -> String+decodeStringWithReplacement = map (either (const '\xFFFD') id) . decodeStringEither++-- |+-- Decode a PSString as UTF-16. Lone surrogates in the input are represented in+-- the output with the Left constructor; characters which were successfully+-- decoded are represented with the Right constructor.+--+decodeStringEither :: PSString -> [Either Word16 Char]+decodeStringEither = unfoldr decode . toUTF16CodeUnits+ where+ decode :: [Word16] -> Maybe (Either Word16 Char, [Word16])+ decode (h:l:rest) | isLead h && isTrail l = Just (Right (unsurrogate h l), rest)+ decode (c:rest) | isSurrogate c = Just (Left c, rest)+ decode (c:rest) = Just (Right (toChar c), rest)+ decode [] = Nothing++ unsurrogate :: Word16 -> Word16 -> Char+ unsurrogate h l = toEnum ((toInt h - 0xD800) * 0x400 + (toInt l - 0xDC00) + 0x10000)++-- |+-- Attempt to decode a PSString as UTF-16 text. This will fail (returning+-- Nothing) if the argument contains lone surrogates.+--+decodeString :: PSString -> Maybe Text+decodeString = hush . decodeEither . BS.pack . concatMap unpair . toUTF16CodeUnits+ where+ unpair w = [highByte w, lowByte w]++ lowByte :: Word16 -> Word8+ lowByte = fromIntegral++ highByte :: Word16 -> Word8+ highByte = fromIntegral . (`shiftR` 8)++ -- Based on a similar function from Data.Text.Encoding for utf8. This is a+ -- safe usage of unsafePerformIO because there are no side effects after+ -- handling any thrown UnicodeExceptions.+ decodeEither :: ByteString -> Either UnicodeException Text+ decodeEither = unsafePerformIO . try . evaluate . decodeUtf16BE++ hush = either (const Nothing) Just++instance IsString PSString where+ fromString a = PSString $ concatMap encodeUTF16 a+ where+ surrogates :: Char -> (Word16, Word16)+ surrogates c = (toWord (h + 0xD800), toWord (l + 0xDC00))+ where (h, l) = divMod (fromEnum c - 0x10000) 0x400++ encodeUTF16 :: Char -> [Word16]+ encodeUTF16 c | fromEnum c > 0xFFFF = [high, low]+ where (high, low) = surrogates c+ encodeUTF16 c = [toWord $ fromEnum c]++instance A.ToJSON PSString where+ toJSON str =+ case decodeString str of+ Just t -> A.toJSON t+ Nothing -> A.toJSON (toUTF16CodeUnits str)++instance A.FromJSON PSString where+ parseJSON a = jsonString <|> arrayOfCodeUnits+ where+ jsonString = fromString <$> A.parseJSON a++ arrayOfCodeUnits = PSString <$> parseArrayOfCodeUnits a++ parseArrayOfCodeUnits :: A.Value -> A.Parser [Word16]+ parseArrayOfCodeUnits = A.withArray "array of UTF-16 code units" (traverse parseCodeUnit . V.toList)++ parseCodeUnit :: A.Value -> A.Parser Word16+ parseCodeUnit b = A.withScientific "two-byte non-negative integer" (maybe (A.typeMismatch "" b) return . toBoundedInteger) b++-- |+-- Pretty print a PSString, using PureScript escape sequences.+--+prettyPrintString :: PSString -> Text+prettyPrintString s = "\"" <> foldMap encodeChar (decodeStringEither s) <> "\""+ where+ encodeChar :: Either Word16 Char -> Text+ encodeChar (Left c) = "\\x" <> showHex' 6 c+ encodeChar (Right c)+ | c == '\t' = "\\t"+ | c == '\r' = "\\r"+ | c == '\n' = "\\n"+ | c == '"' = "\\\""+ | c == '\'' = "\\\'"+ | c == '\\' = "\\\\"+ | shouldPrint c = T.singleton c+ | otherwise = "\\x" <> showHex' 6 (Char.ord c)++ -- Note we do not use Data.Char.isPrint here because that includes things+ -- like zero-width spaces and combining punctuation marks, which could be+ -- confusing to print unescaped.+ shouldPrint :: Char -> Bool+ -- The standard space character, U+20 SPACE, is the only space char we should+ -- print without escaping+ shouldPrint ' ' = True+ shouldPrint c =+ Char.generalCategory c `elem`+ [ Char.UppercaseLetter+ , Char.LowercaseLetter+ , Char.TitlecaseLetter+ , Char.OtherLetter+ , Char.DecimalNumber+ , Char.LetterNumber+ , Char.OtherNumber+ , Char.ConnectorPunctuation+ , Char.DashPunctuation+ , Char.OpenPunctuation+ , Char.ClosePunctuation+ , Char.InitialQuote+ , Char.FinalQuote+ , Char.OtherPunctuation+ , Char.MathSymbol+ , Char.CurrencySymbol+ , Char.ModifierSymbol+ , Char.OtherSymbol+ ]++-- |+-- Pretty print a PSString, using JavaScript escape sequences. Intended for+-- use in compiled JS output.+--+prettyPrintStringJS :: PSString -> Text+prettyPrintStringJS s = "\"" <> foldMap encodeChar (toUTF16CodeUnits s) <> "\""+ where+ encodeChar :: Word16 -> Text+ encodeChar c | c > 0xFF = "\\u" <> showHex' 4 c+ encodeChar c | c > 0x7E || c < 0x20 = "\\x" <> showHex' 2 c+ encodeChar c | toChar c == '\b' = "\\b"+ encodeChar c | toChar c == '\t' = "\\t"+ encodeChar c | toChar c == '\n' = "\\n"+ encodeChar c | toChar c == '\v' = "\\v"+ encodeChar c | toChar c == '\f' = "\\f"+ encodeChar c | toChar c == '\r' = "\\r"+ encodeChar c | toChar c == '"' = "\\\""+ encodeChar c | toChar c == '\\' = "\\\\"+ encodeChar c = T.singleton $ toChar c++showHex' :: Enum a => Int -> a -> Text+showHex' width c =+ let hs = showHex (fromEnum c) "" in+ T.pack (replicate (width - length hs) '0' <> hs)++isLead :: Word16 -> Bool+isLead h = h >= 0xD800 && h <= 0xDBFF++isTrail :: Word16 -> Bool+isTrail l = l >= 0xDC00 && l <= 0xDFFF++isSurrogate :: Word16 -> Bool+isSurrogate c = isLead c || isTrail c++toChar :: Word16 -> Char+toChar = toEnum . fromIntegral++toWord :: Int -> Word16+toWord = fromIntegral++toInt :: Word16 -> Int+toInt = fromIntegral++mkString :: Text -> PSString+mkString = fromString . T.unpack
+ src/Language/PureScript/Roles.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Data types for roles.+--+module Language.PureScript.Roles+ ( Role(..)+ , displayRole+ ) where++import Prelude.Compat++import Codec.Serialise (Serialise)+import Control.DeepSeq (NFData)+import qualified Data.Aeson as A+import qualified Data.Aeson.TH as A+import Data.Text (Text)+import GHC.Generics (Generic)++-- |+-- The role of a type constructor's parameter.+data Role+ = Nominal+ -- ^ This parameter's identity affects the representation of the type it is+ -- parameterising.+ | Representational+ -- ^ This parameter's representation affects the representation of the type it+ -- is parameterising.+ | Phantom+ -- ^ This parameter has no effect on the representation of the type it is+ -- parameterising.+ deriving (Show, Eq, Ord, Generic)++instance NFData Role+instance Serialise Role++$(A.deriveJSON A.defaultOptions ''Role)++displayRole :: Role -> Text+displayRole r = case r of+ Nominal -> "nominal"+ Representational -> "representational"+ Phantom -> "phantom"
+ src/Language/PureScript/Traversals.hs view
@@ -0,0 +1,27 @@+-- | Common functions for implementing generic traversals+module Language.PureScript.Traversals where++import Prelude.Compat++fstM :: (Functor f) => (a -> f c) -> (a, b) -> f (c, b)+fstM f (a, b) = (, b) <$> f a++sndM :: (Functor f) => (b -> f c) -> (a, b) -> f (a, c)+sndM f (a, b) = (a, ) <$> f b++thirdM :: (Functor f) => (c -> f d) -> (a, b, c) -> f (a, b, d)+thirdM f (a, b, c) = (a, b, ) <$> f c++pairM :: (Applicative f) => (a -> f c) -> (b -> f d) -> (a, b) -> f (c, d)+pairM f g (a, b) = (,) <$> f a <*> g b++maybeM :: (Applicative f) => (a -> f b) -> Maybe a -> f (Maybe b)+maybeM _ Nothing = pure Nothing+maybeM f (Just a) = Just <$> f a++eitherM :: (Applicative f) => (a -> f c) -> (b -> f d) -> Either a b -> f (Either c d)+eitherM f _ (Left a) = Left <$> f a+eitherM _ g (Right b) = Right <$> g b++defS :: (Monad m) => st -> val -> m (st, val)+defS s val = return (s, val)
+ src/Language/PureScript/TypeClassDictionaries.hs view
@@ -0,0 +1,46 @@+module Language.PureScript.TypeClassDictionaries where++import Prelude.Compat++import GHC.Generics (Generic)+import Control.DeepSeq (NFData)+import Data.Text (Text, pack)++import Language.PureScript.AST.Declarations.ChainId (ChainId)+import Language.PureScript.Names+import Language.PureScript.Types++--+-- Data representing a type class dictionary which is in scope+--+data TypeClassDictionaryInScope v+ = TypeClassDictionaryInScope {+ -- | The instance chain+ tcdChain :: Maybe ChainId+ -- | Index of the instance chain+ , tcdIndex :: Integer+ -- | The value with which the dictionary can be accessed at runtime+ , tcdValue :: v+ -- | How to obtain this instance via superclass relationships+ , tcdPath :: [(Qualified (ProperName 'ClassName), Integer)]+ -- | The name of the type class to which this type class instance applies+ , tcdClassName :: Qualified (ProperName 'ClassName)+ -- | Quantification of type variables in the instance head and dependencies+ , tcdForAll :: [(Text, SourceType)]+ -- | The kinds to which this type class instance applies+ , tcdInstanceKinds :: [SourceType]+ -- | The types to which this type class instance applies+ , tcdInstanceTypes :: [SourceType]+ -- | Type class dependencies which must be satisfied to construct this dictionary+ , tcdDependencies :: Maybe [SourceConstraint]+ }+ deriving (Show, Functor, Foldable, Traversable, Generic)++instance NFData v => NFData (TypeClassDictionaryInScope v)++type NamedDict = TypeClassDictionaryInScope (Qualified Ident)++-- | Generate a name for a superclass reference which can be used in+-- generated code.+superclassName :: Qualified (ProperName 'ClassName) -> Integer -> Text+superclassName pn index = runProperName (disqualify pn) <> pack (show index)
+ src/Language/PureScript/Types.hs view
@@ -0,0 +1,788 @@+-- |+-- Data types for types+--+module Language.PureScript.Types where++import Prelude.Compat+import Protolude (ordNub)++import Codec.Serialise (Serialise)+import Control.Applicative ((<|>))+import Control.Arrow (first, second)+import Control.DeepSeq (NFData)+import Control.Monad ((<=<), (>=>))+import Data.Aeson ((.:), (.:?), (.!=), (.=))+import qualified Data.Aeson as A+import qualified Data.Aeson.Types as A+import Data.Foldable (fold)+import qualified Data.IntSet as IS+import Data.List (sort, sortOn)+import Data.Maybe (fromMaybe, isJust)+import qualified Data.Set as S+import Data.Text (Text)+import qualified Data.Text as T+import GHC.Generics (Generic)++import Language.PureScript.AST.SourcePos+import qualified Language.PureScript.Constants.Prim as C+import Language.PureScript.Names+import Language.PureScript.Label (Label)+import Language.PureScript.PSString (PSString)++import Lens.Micro (Lens', (^.), set)++type SourceType = Type SourceAnn+type SourceConstraint = Constraint SourceAnn++-- |+-- An identifier for the scope of a skolem variable+--+newtype SkolemScope = SkolemScope { runSkolemScope :: Int }+ deriving (Show, Eq, Ord, A.ToJSON, A.FromJSON, Generic)++instance NFData SkolemScope+instance Serialise SkolemScope++-- |+-- The type of types+--+data Type a+ -- | A unification variable of type Type+ = TUnknown a Int+ -- | A named type variable+ | TypeVar a Text+ -- | A type-level string+ | TypeLevelString a PSString+ -- | A type wildcard, as would appear in a partial type synonym+ | TypeWildcard a (Maybe Text)+ -- | A type constructor+ | TypeConstructor a (Qualified (ProperName 'TypeName))+ -- | A type operator. This will be desugared into a type constructor during the+ -- "operators" phase of desugaring.+ | TypeOp a (Qualified (OpName 'TypeOpName))+ -- | A type application+ | TypeApp a (Type a) (Type a)+ -- | Explicit kind application+ | KindApp a (Type a) (Type a)+ -- | Forall quantifier+ | ForAll a Text (Maybe (Type a)) (Type a) (Maybe SkolemScope)+ -- | A type with a set of type class constraints+ | ConstrainedType a (Constraint a) (Type a)+ -- | A skolem constant+ | Skolem a Text (Maybe (Type a)) Int SkolemScope+ -- | An empty row+ | REmpty a+ -- | A non-empty row+ | RCons a Label (Type a) (Type a)+ -- | A type with a kind annotation+ | KindedType a (Type a) (Type a)+ -- | Binary operator application. During the rebracketing phase of desugaring,+ -- this data constructor will be removed.+ | BinaryNoParensType a (Type a) (Type a) (Type a)+ -- | Explicit parentheses. During the rebracketing phase of desugaring, this+ -- data constructor will be removed.+ --+ -- Note: although it seems this constructor is not used, it _is_ useful,+ -- since it prevents certain traversals from matching.+ | ParensInType a (Type a)+ deriving (Show, Generic, Functor, Foldable, Traversable)++instance NFData a => NFData (Type a)+instance Serialise a => Serialise (Type a)++srcTUnknown :: Int -> SourceType+srcTUnknown = TUnknown NullSourceAnn++srcTypeVar :: Text -> SourceType+srcTypeVar = TypeVar NullSourceAnn++srcTypeLevelString :: PSString -> SourceType+srcTypeLevelString = TypeLevelString NullSourceAnn++srcTypeWildcard :: SourceType+srcTypeWildcard = TypeWildcard NullSourceAnn Nothing++srcTypeConstructor :: Qualified (ProperName 'TypeName) -> SourceType+srcTypeConstructor = TypeConstructor NullSourceAnn++srcTypeOp :: Qualified (OpName 'TypeOpName) -> SourceType+srcTypeOp = TypeOp NullSourceAnn++srcTypeApp :: SourceType -> SourceType -> SourceType+srcTypeApp = TypeApp NullSourceAnn++srcKindApp :: SourceType -> SourceType -> SourceType+srcKindApp = KindApp NullSourceAnn++srcForAll :: Text -> Maybe SourceType -> SourceType -> Maybe SkolemScope -> SourceType+srcForAll = ForAll NullSourceAnn++srcConstrainedType :: SourceConstraint -> SourceType -> SourceType+srcConstrainedType = ConstrainedType NullSourceAnn++srcREmpty :: SourceType+srcREmpty = REmpty NullSourceAnn++srcRCons :: Label -> SourceType -> SourceType -> SourceType+srcRCons = RCons NullSourceAnn++srcKindedType :: SourceType -> SourceType -> SourceType+srcKindedType = KindedType NullSourceAnn++srcBinaryNoParensType :: SourceType -> SourceType -> SourceType -> SourceType+srcBinaryNoParensType = BinaryNoParensType NullSourceAnn++srcParensInType :: SourceType -> SourceType+srcParensInType = ParensInType NullSourceAnn++pattern REmptyKinded :: forall a. a -> Maybe (Type a) -> Type a+pattern REmptyKinded ann mbK <- (toREmptyKinded -> Just (ann, mbK))++toREmptyKinded :: forall a. Type a -> Maybe (a, Maybe (Type a))+toREmptyKinded (REmpty ann) = Just (ann, Nothing)+toREmptyKinded (KindApp _ (REmpty ann) k) = Just (ann, Just k)+toREmptyKinded _ = Nothing++isREmpty :: forall a. Type a -> Bool+isREmpty = isJust . toREmptyKinded++-- | Additional data relevant to type class constraints+data ConstraintData+ = PartialConstraintData [[Text]] Bool+ -- ^ Data to accompany a Partial constraint generated by the exhaustivity checker.+ -- It contains (rendered) binder information for those binders which were+ -- not matched, and a flag indicating whether the list was truncated or not.+ -- Note: we use 'Text' here because using 'Binder' would introduce a cyclic+ -- dependency in the module graph.+ deriving (Show, Eq, Ord, Generic)++instance NFData ConstraintData+instance Serialise ConstraintData++-- | A typeclass constraint+data Constraint a = Constraint+ { constraintAnn :: a+ -- ^ constraint annotation+ , constraintClass :: Qualified (ProperName 'ClassName)+ -- ^ constraint class name+ , constraintKindArgs :: [Type a]+ -- ^ kind arguments+ , constraintArgs :: [Type a]+ -- ^ type arguments+ , constraintData :: Maybe ConstraintData+ -- ^ additional data relevant to this constraint+ } deriving (Show, Generic, Functor, Foldable, Traversable)++instance NFData a => NFData (Constraint a)+instance Serialise a => Serialise (Constraint a)++srcConstraint :: Qualified (ProperName 'ClassName) -> [SourceType] -> [SourceType] -> Maybe ConstraintData -> SourceConstraint+srcConstraint = Constraint NullSourceAnn++mapConstraintArgs :: ([Type a] -> [Type a]) -> Constraint a -> Constraint a+mapConstraintArgs f c = c { constraintArgs = f (constraintArgs c) }++overConstraintArgs :: Functor f => ([Type a] -> f [Type a]) -> Constraint a -> f (Constraint a)+overConstraintArgs f c = (\args -> c { constraintArgs = args }) <$> f (constraintArgs c)++mapConstraintKindArgs :: ([Type a] -> [Type a]) -> Constraint a -> Constraint a+mapConstraintKindArgs f c = c { constraintKindArgs = f (constraintKindArgs c) }++overConstraintKindArgs :: Functor f => ([Type a] -> f [Type a]) -> Constraint a -> f (Constraint a)+overConstraintKindArgs f c = (\args -> c { constraintKindArgs = args }) <$> f (constraintKindArgs c)++mapConstraintArgsAll :: ([Type a] -> [Type a]) -> Constraint a -> Constraint a+mapConstraintArgsAll f c =+ c { constraintKindArgs = f (constraintKindArgs c)+ , constraintArgs = f (constraintArgs c)+ }++overConstraintArgsAll :: Applicative f => ([Type a] -> f [Type a]) -> Constraint a -> f (Constraint a)+overConstraintArgsAll f c =+ (\a b -> c { constraintKindArgs = a, constraintArgs = b })+ <$> f (constraintKindArgs c)+ <*> f (constraintArgs c)++constraintDataToJSON :: ConstraintData -> A.Value+constraintDataToJSON (PartialConstraintData bs trunc) =+ A.object+ [ "contents" .= (bs, trunc)+ ]++constraintToJSON :: (a -> A.Value) -> Constraint a -> A.Value+constraintToJSON annToJSON Constraint {..} =+ A.object+ [ "constraintAnn" .= annToJSON constraintAnn+ , "constraintClass" .= constraintClass+ , "constraintKindArgs" .= fmap (typeToJSON annToJSON) constraintKindArgs+ , "constraintArgs" .= fmap (typeToJSON annToJSON) constraintArgs+ , "constraintData" .= fmap constraintDataToJSON constraintData+ ]++typeToJSON :: forall a. (a -> A.Value) -> Type a -> A.Value+typeToJSON annToJSON ty =+ case ty of+ TUnknown a b ->+ variant "TUnknown" a b+ TypeVar a b ->+ variant "TypeVar" a b+ TypeLevelString a b ->+ variant "TypeLevelString" a b+ TypeWildcard a b ->+ variant "TypeWildcard" a b+ TypeConstructor a b ->+ variant "TypeConstructor" a b+ TypeOp a b ->+ variant "TypeOp" a b+ TypeApp a b c ->+ variant "TypeApp" a (go b, go c)+ KindApp a b c ->+ variant "KindApp" a (go b, go c)+ ForAll a b c d e ->+ case c of+ Nothing -> variant "ForAll" a (b, go d, e)+ Just k -> variant "ForAll" a (b, go k, go d, e)+ ConstrainedType a b c ->+ variant "ConstrainedType" a (constraintToJSON annToJSON b, go c)+ Skolem a b c d e ->+ variant "Skolem" a (b, go <$> c, d, e)+ REmpty a ->+ nullary "REmpty" a+ RCons a b c d ->+ variant "RCons" a (b, go c, go d)+ KindedType a b c ->+ variant "KindedType" a (go b, go c)+ BinaryNoParensType a b c d ->+ variant "BinaryNoParensType" a (go b, go c, go d)+ ParensInType a b ->+ variant "ParensInType" a (go b)+ where+ go :: Type a -> A.Value+ go = typeToJSON annToJSON++ variant :: A.ToJSON b => String -> a -> b -> A.Value+ variant tag ann contents =+ A.object+ [ "tag" .= tag+ , "annotation" .= annToJSON ann+ , "contents" .= contents+ ]++ nullary :: String -> a -> A.Value+ nullary tag ann =+ A.object+ [ "tag" .= tag+ , "annotation" .= annToJSON ann+ ]++instance A.ToJSON a => A.ToJSON (Type a) where+ toJSON = typeToJSON A.toJSON++instance A.ToJSON a => A.ToJSON (Constraint a) where+ toJSON = constraintToJSON A.toJSON++instance A.ToJSON ConstraintData where+ toJSON = constraintDataToJSON++constraintDataFromJSON :: A.Value -> A.Parser ConstraintData+constraintDataFromJSON = A.withObject "PartialConstraintData" $ \o -> do+ (bs, trunc) <- o .: "contents"+ pure $ PartialConstraintData bs trunc++constraintFromJSON :: forall a. A.Parser a -> (A.Value -> A.Parser a) -> A.Value -> A.Parser (Constraint a)+constraintFromJSON defaultAnn annFromJSON = A.withObject "Constraint" $ \o -> do+ constraintAnn <- (o .: "constraintAnn" >>= annFromJSON) <|> defaultAnn+ constraintClass <- o .: "constraintClass"+ constraintKindArgs <- o .:? "constraintKindArgs" .!= [] >>= traverse (typeFromJSON defaultAnn annFromJSON)+ constraintArgs <- o .: "constraintArgs" >>= traverse (typeFromJSON defaultAnn annFromJSON)+ constraintData <- o .: "constraintData" >>= traverse constraintDataFromJSON+ pure $ Constraint {..}++typeFromJSON :: forall a. A.Parser a -> (A.Value -> A.Parser a) -> A.Value -> A.Parser (Type a)+typeFromJSON defaultAnn annFromJSON = A.withObject "Type" $ \o -> do+ tag <- o .: "tag"+ a <- (o .: "annotation" >>= annFromJSON) <|> defaultAnn+ let+ contents :: A.FromJSON b => A.Parser b+ contents = o .: "contents"+ case tag of+ "TUnknown" ->+ TUnknown a <$> contents+ "TypeVar" ->+ TypeVar a <$> contents+ "TypeLevelString" ->+ TypeLevelString a <$> contents+ "TypeWildcard" -> do+ b <- contents <|> pure Nothing+ pure $ TypeWildcard a b+ "TypeConstructor" ->+ TypeConstructor a <$> contents+ "TypeOp" ->+ TypeOp a <$> contents+ "TypeApp" -> do+ (b, c) <- contents+ TypeApp a <$> go b <*> go c+ "KindApp" -> do+ (b, c) <- contents+ KindApp a <$> go b <*> go c+ "ForAll" -> do+ let+ withoutMbKind = do+ (b, c, d) <- contents+ ForAll a b Nothing <$> go c <*> pure d+ withMbKind = do+ (b, c, d, e) <- contents+ ForAll a b <$> (Just <$> go c) <*> go d <*> pure e+ withMbKind <|> withoutMbKind+ "ConstrainedType" -> do+ (b, c) <- contents+ ConstrainedType a <$> constraintFromJSON defaultAnn annFromJSON b <*> go c+ "Skolem" -> do+ (b, c, d, e) <- contents+ c' <- traverse go c+ pure $ Skolem a b c' d e+ "REmpty" ->+ pure $ REmpty a+ "RCons" -> do+ (b, c, d) <- contents+ RCons a b <$> go c <*> go d+ "KindedType" -> do+ (b, c) <- contents+ KindedType a <$> go b <*> go c+ "BinaryNoParensType" -> do+ (b, c, d) <- contents+ BinaryNoParensType a <$> go b <*> go c <*> go d+ "ParensInType" -> do+ b <- contents+ ParensInType a <$> go b+ -- Backwards compatability for kinds+ "KUnknown" ->+ TUnknown a <$> contents+ "Row" ->+ TypeApp a (TypeConstructor a C.Row) <$> (go =<< contents)+ "FunKind" -> do+ (b, c) <- contents+ TypeApp a . TypeApp a (TypeConstructor a C.Function) <$> go b <*> go c+ "NamedKind" ->+ TypeConstructor a <$> contents+ other ->+ fail $ "Unrecognised tag: " ++ other+ where+ go :: A.Value -> A.Parser (Type a)+ go = typeFromJSON defaultAnn annFromJSON++-- These overlapping instances exist to preserve compatibility for common+-- instances which have a sensible default for missing annotations.+instance {-# OVERLAPPING #-} A.FromJSON (Type SourceAnn) where+ parseJSON = typeFromJSON (pure NullSourceAnn) A.parseJSON++instance {-# OVERLAPPING #-} A.FromJSON (Type ()) where+ parseJSON = typeFromJSON (pure ()) A.parseJSON++instance {-# OVERLAPPING #-} A.FromJSON a => A.FromJSON (Type a) where+ parseJSON = typeFromJSON (fail "Invalid annotation") A.parseJSON++instance {-# OVERLAPPING #-} A.FromJSON (Constraint SourceAnn) where+ parseJSON = constraintFromJSON (pure NullSourceAnn) A.parseJSON++instance {-# OVERLAPPING #-} A.FromJSON (Constraint ()) where+ parseJSON = constraintFromJSON (pure ()) A.parseJSON++instance {-# OVERLAPPING #-} A.FromJSON a => A.FromJSON (Constraint a) where+ parseJSON = constraintFromJSON (fail "Invalid annotation") A.parseJSON++instance A.FromJSON ConstraintData where+ parseJSON = constraintDataFromJSON++data RowListItem a = RowListItem+ { rowListAnn :: a+ , rowListLabel :: Label+ , rowListType :: Type a+ } deriving (Show, Generic, Functor, Foldable, Traversable)++srcRowListItem :: Label -> SourceType -> RowListItem SourceAnn+srcRowListItem = RowListItem NullSourceAnn++-- | Convert a row to a list of pairs of labels and types+rowToList :: Type a -> ([RowListItem a], Type a)+rowToList = go where+ go (RCons ann name ty row) =+ first (RowListItem ann name ty :) (rowToList row)+ go r = ([], r)++-- | Convert a row to a list of pairs of labels and types, sorted by the labels.+rowToSortedList :: Type a -> ([RowListItem a], Type a)+rowToSortedList = first (sortOn rowListLabel) . rowToList++-- | Convert a list of labels and types to a row+rowFromList :: ([RowListItem a], Type a) -> Type a+rowFromList (xs, r) = foldr (\(RowListItem ann name ty) -> RCons ann name ty) r xs++-- | Align two rows of types, splitting them into three parts:+--+-- * Those types which appear in both rows+-- * Those which appear only on the left+-- * Those which appear only on the right+--+-- Note: importantly, we preserve the order of the types with a given label.+alignRowsWith+ :: (Type a -> Type a -> r)+ -> Type a+ -> Type a+ -> ([r], (([RowListItem a], Type a), ([RowListItem a], Type a)))+alignRowsWith f ty1 ty2 = go s1 s2 where+ (s1, tail1) = rowToSortedList ty1+ (s2, tail2) = rowToSortedList ty2++ go [] r = ([], (([], tail1), (r, tail2)))+ go r [] = ([], ((r, tail1), ([], tail2)))+ go lhs@(RowListItem a1 l1 t1 : r1) rhs@(RowListItem a2 l2 t2 : r2)+ | l1 < l2 = (second . first . first) (RowListItem a1 l1 t1 :) (go r1 rhs)+ | l2 < l1 = (second . second . first) (RowListItem a2 l2 t2 :) (go lhs r2)+ | otherwise = first (f t1 t2 :) (go r1 r2)++-- | Check whether a type is a monotype+isMonoType :: Type a -> Bool+isMonoType ForAll{} = False+isMonoType (ParensInType _ t) = isMonoType t+isMonoType (KindedType _ t _) = isMonoType t+isMonoType _ = True++-- | Universally quantify a type+mkForAll :: [(a, (Text, Maybe (Type a)))] -> Type a -> Type a+mkForAll args ty = foldr (\(ann, (arg, mbK)) t -> ForAll ann arg mbK t Nothing) ty args++-- | Replace a type variable, taking into account variable shadowing+replaceTypeVars :: Text -> Type a -> Type a -> Type a+replaceTypeVars v r = replaceAllTypeVars [(v, r)]++-- | Replace named type variables with types+replaceAllTypeVars :: [(Text, Type a)] -> Type a -> Type a+replaceAllTypeVars = go [] where+ go :: [Text] -> [(Text, Type a)] -> Type a -> Type a+ go _ m (TypeVar ann v) = fromMaybe (TypeVar ann v) (v `lookup` m)+ go bs m (TypeApp ann t1 t2) = TypeApp ann (go bs m t1) (go bs m t2)+ go bs m (KindApp ann t1 t2) = KindApp ann (go bs m t1) (go bs m t2)+ go bs m (ForAll ann v mbK t sco)+ | v `elem` keys = go bs (filter ((/= v) . fst) m) $ ForAll ann v mbK' t sco+ | v `elem` usedVars =+ let v' = genName v (keys ++ bs ++ usedVars)+ t' = go bs [(v, TypeVar ann v')] t+ in ForAll ann v' mbK' (go (v' : bs) m t') sco+ | otherwise = ForAll ann v mbK' (go (v : bs) m t) sco+ where+ mbK' = go bs m <$> mbK+ keys = map fst m+ usedVars = concatMap (usedTypeVariables . snd) m+ go bs m (ConstrainedType ann c t) = ConstrainedType ann (mapConstraintArgsAll (map (go bs m)) c) (go bs m t)+ go bs m (RCons ann name' t r) = RCons ann name' (go bs m t) (go bs m r)+ go bs m (KindedType ann t k) = KindedType ann (go bs m t) (go bs m k)+ go bs m (BinaryNoParensType ann t1 t2 t3) = BinaryNoParensType ann (go bs m t1) (go bs m t2) (go bs m t3)+ go bs m (ParensInType ann t) = ParensInType ann (go bs m t)+ go _ _ ty = ty++ genName orig inUse = try' 0 where+ try' :: Integer -> Text+ try' n | (orig <> T.pack (show n)) `elem` inUse = try' (n + 1)+ | otherwise = orig <> T.pack (show n)++-- | Collect all type variables appearing in a type+usedTypeVariables :: Type a -> [Text]+usedTypeVariables = ordNub . everythingOnTypes (++) go where+ go (TypeVar _ v) = [v]+ go _ = []++-- | Collect all free type variables appearing in a type+freeTypeVariables :: Type a -> [Text]+freeTypeVariables = ordNub . fmap snd . sort . go 0 [] where+ -- Tracks kind levels so that variables appearing in kind annotations are listed first.+ go :: Int -> [Text] -> Type a -> [(Int, Text)]+ go lvl bound (TypeVar _ v) | v `notElem` bound = [(lvl, v)]+ go lvl bound (TypeApp _ t1 t2) = go lvl bound t1 ++ go lvl bound t2+ go lvl bound (KindApp _ t1 t2) = go lvl bound t1 ++ go (lvl - 1) bound t2+ go lvl bound (ForAll _ v mbK t _) = foldMap (go (lvl - 1) bound) mbK ++ go lvl (v : bound) t+ go lvl bound (ConstrainedType _ c t) = foldMap (go (lvl - 1) bound) (constraintKindArgs c) ++ foldMap (go lvl bound) (constraintArgs c) ++ go lvl bound t+ go lvl bound (RCons _ _ t r) = go lvl bound t ++ go lvl bound r+ go lvl bound (KindedType _ t k) = go lvl bound t ++ go (lvl - 1) bound k+ go lvl bound (BinaryNoParensType _ t1 t2 t3) = go lvl bound t1 ++ go lvl bound t2 ++ go lvl bound t3+ go lvl bound (ParensInType _ t) = go lvl bound t+ go _ _ _ = []++-- | Collect a complete set of kind-annotated quantifiers at the front of a type.+completeBinderList :: Type a -> Maybe ([(a, (Text, Type a))], Type a)+completeBinderList = go []+ where+ go acc = \case+ ForAll _ _ Nothing _ _ -> Nothing+ ForAll ann var (Just k) ty _ -> go ((ann, (var, k)) : acc) ty+ ty -> Just (reverse acc, ty)++-- | Universally quantify over all type variables appearing free in a type+quantify :: Type a -> Type a+quantify ty = foldr (\arg t -> ForAll (getAnnForType ty) arg Nothing t Nothing) ty $ freeTypeVariables ty++-- | Move all universal quantifiers to the front of a type+moveQuantifiersToFront :: Type a -> Type a+moveQuantifiersToFront = go [] [] where+ go qs cs (ForAll ann q mbK ty sco) = go ((ann, q, sco, mbK) : qs) cs ty+ go qs cs (ConstrainedType ann c ty) = go qs ((ann, c) : cs) ty+ go qs cs ty = foldl (\ty' (ann, q, sco, mbK) -> ForAll ann q mbK ty' sco) (foldl (\ty' (ann, c) -> ConstrainedType ann c ty') ty cs) qs++-- | Check if a type contains wildcards+containsWildcards :: Type a -> Bool+containsWildcards = everythingOnTypes (||) go where+ go :: Type a -> Bool+ go TypeWildcard{} = True+ go _ = False++-- | Check if a type contains `forall`+containsForAll :: Type a -> Bool+containsForAll = everythingOnTypes (||) go where+ go :: Type a -> Bool+ go ForAll{} = True+ go _ = False++unknowns :: Type a -> IS.IntSet+unknowns = everythingOnTypes (<>) go where+ go :: Type a -> IS.IntSet+ go (TUnknown _ u) = IS.singleton u+ go _ = mempty++containsUnknowns :: Type a -> Bool+containsUnknowns = everythingOnTypes (||) go where+ go :: Type a -> Bool+ go TUnknown{} = True+ go _ = False++eraseKindApps :: Type a -> Type a+eraseKindApps = everywhereOnTypes $ \case+ KindApp _ ty _ -> ty+ ConstrainedType ann con ty ->+ ConstrainedType ann (con { constraintKindArgs = [] }) ty+ other -> other++eraseForAllKindAnnotations :: Type a -> Type a+eraseForAllKindAnnotations = removeAmbiguousVars . removeForAllKinds+ where+ removeForAllKinds = everywhereOnTypes $ \case+ ForAll ann arg _ ty sco ->+ ForAll ann arg Nothing ty sco+ other -> other++ removeAmbiguousVars = everywhereOnTypes $ \case+ fa@(ForAll _ arg _ ty _)+ | arg `elem` freeTypeVariables ty -> fa+ | otherwise -> ty+ other -> other++unapplyTypes :: Type a -> (Type a, [Type a], [Type a])+unapplyTypes = goTypes []+ where+ goTypes acc (TypeApp _ a b) = goTypes (b : acc) a+ goTypes acc a = let (ty, kinds) = goKinds [] a in (ty, kinds, acc)++ goKinds acc (KindApp _ a b) = goKinds (b : acc) a+ goKinds acc a = (a, acc)++unapplyConstraints :: Type a -> ([Constraint a], Type a)+unapplyConstraints = go []+ where+ go acc (ConstrainedType _ con ty) = go (con : acc) ty+ go acc ty = (reverse acc, ty)++everywhereOnTypes :: (Type a -> Type a) -> Type a -> Type a+everywhereOnTypes f = go where+ go (TypeApp ann t1 t2) = f (TypeApp ann (go t1) (go t2))+ go (KindApp ann t1 t2) = f (KindApp ann (go t1) (go t2))+ go (ForAll ann arg mbK ty sco) = f (ForAll ann arg (go <$> mbK) (go ty) sco)+ go (ConstrainedType ann c ty) = f (ConstrainedType ann (mapConstraintArgsAll (map go) c) (go ty))+ go (RCons ann name ty rest) = f (RCons ann name (go ty) (go rest))+ go (KindedType ann ty k) = f (KindedType ann (go ty) (go k))+ go (BinaryNoParensType ann t1 t2 t3) = f (BinaryNoParensType ann (go t1) (go t2) (go t3))+ go (ParensInType ann t) = f (ParensInType ann (go t))+ go other = f other++everywhereOnTypesTopDown :: (Type a -> Type a) -> Type a -> Type a+everywhereOnTypesTopDown f = go . f where+ go (TypeApp ann t1 t2) = TypeApp ann (go (f t1)) (go (f t2))+ go (KindApp ann t1 t2) = KindApp ann (go (f t1)) (go (f t2))+ go (ForAll ann arg mbK ty sco) = ForAll ann arg (go . f <$> mbK) (go (f ty)) sco+ go (ConstrainedType ann c ty) = ConstrainedType ann (mapConstraintArgsAll (map (go . f)) c) (go (f ty))+ go (RCons ann name ty rest) = RCons ann name (go (f ty)) (go (f rest))+ go (KindedType ann ty k) = KindedType ann (go (f ty)) (go (f k))+ go (BinaryNoParensType ann t1 t2 t3) = BinaryNoParensType ann (go (f t1)) (go (f t2)) (go (f t3))+ go (ParensInType ann t) = ParensInType ann (go (f t))+ go other = f other++everywhereOnTypesM :: Monad m => (Type a -> m (Type a)) -> Type a -> m (Type a)+everywhereOnTypesM f = go where+ go (TypeApp ann t1 t2) = (TypeApp ann <$> go t1 <*> go t2) >>= f+ go (KindApp ann t1 t2) = (KindApp ann <$> go t1 <*> go t2) >>= f+ go (ForAll ann arg mbK ty sco) = (ForAll ann arg <$> traverse go mbK <*> go ty <*> pure sco) >>= f+ go (ConstrainedType ann c ty) = (ConstrainedType ann <$> overConstraintArgsAll (mapM go) c <*> go ty) >>= f+ go (RCons ann name ty rest) = (RCons ann name <$> go ty <*> go rest) >>= f+ go (KindedType ann ty k) = (KindedType ann <$> go ty <*> go k) >>= f+ go (BinaryNoParensType ann t1 t2 t3) = (BinaryNoParensType ann <$> go t1 <*> go t2 <*> go t3) >>= f+ go (ParensInType ann t) = (ParensInType ann <$> go t) >>= f+ go other = f other++everywhereWithScopeOnTypesM :: Monad m => S.Set Text -> (S.Set Text -> Type a -> m (Type a)) -> Type a -> m (Type a)+everywhereWithScopeOnTypesM s0 f = go s0 where+ go s (TypeApp ann t1 t2) = (TypeApp ann <$> go s t1 <*> go s t2) >>= f s+ go s (KindApp ann t1 t2) = (KindApp ann <$> go s t1 <*> go s t2) >>= f s+ go s (ForAll ann arg mbK ty sco) = (ForAll ann arg <$> traverse (go s) mbK <*> go (S.insert arg s) ty <*> pure sco) >>= f s+ go s (ConstrainedType ann c ty) = (ConstrainedType ann <$> overConstraintArgsAll (traverse (go s)) c <*> go s ty) >>= f s+ go s (RCons ann name ty rest) = (RCons ann name <$> go s ty <*> go s rest) >>= f s+ go s (KindedType ann ty k) = (KindedType ann <$> go s ty <*> go s k) >>= f s+ go s (BinaryNoParensType ann t1 t2 t3) = (BinaryNoParensType ann <$> go s t1 <*> go s t2 <*> go s t3) >>= f s+ go s (ParensInType ann t) = (ParensInType ann <$> go s t) >>= f s+ go s other = f s other++everywhereOnTypesTopDownM :: Monad m => (Type a -> m (Type a)) -> Type a -> m (Type a)+everywhereOnTypesTopDownM f = go <=< f where+ go (TypeApp ann t1 t2) = TypeApp ann <$> (f t1 >>= go) <*> (f t2 >>= go)+ go (KindApp ann t1 t2) = KindApp ann <$> (f t1 >>= go) <*> (f t2 >>= go)+ go (ForAll ann arg mbK ty sco) = ForAll ann arg <$> traverse (f >=> go) mbK <*> (f ty >>= go) <*> pure sco+ go (ConstrainedType ann c ty) = ConstrainedType ann <$> overConstraintArgsAll (mapM (go <=< f)) c <*> (f ty >>= go)+ go (RCons ann name ty rest) = RCons ann name <$> (f ty >>= go) <*> (f rest >>= go)+ go (KindedType ann ty k) = KindedType ann <$> (f ty >>= go) <*> (f k >>= go)+ go (BinaryNoParensType ann t1 t2 t3) = BinaryNoParensType ann <$> (f t1 >>= go) <*> (f t2 >>= go) <*> (f t3 >>= go)+ go (ParensInType ann t) = ParensInType ann <$> (f t >>= go)+ go other = f other++everythingOnTypes :: (r -> r -> r) -> (Type a -> r) -> Type a -> r+everythingOnTypes (<+>) f = go where+ go t@(TypeApp _ t1 t2) = f t <+> go t1 <+> go t2+ go t@(KindApp _ t1 t2) = f t <+> go t1 <+> go t2+ go t@(ForAll _ _ (Just k) ty _) = f t <+> go k <+> go ty+ go t@(ForAll _ _ _ ty _) = f t <+> go ty+ go t@(ConstrainedType _ c ty) = foldl (<+>) (f t) (map go (constraintKindArgs c) ++ map go (constraintArgs c)) <+> go ty+ go t@(RCons _ _ ty rest) = f t <+> go ty <+> go rest+ go t@(KindedType _ ty k) = f t <+> go ty <+> go k+ go t@(BinaryNoParensType _ t1 t2 t3) = f t <+> go t1 <+> go t2 <+> go t3+ go t@(ParensInType _ t1) = f t <+> go t1+ go other = f other++everythingWithContextOnTypes :: s -> r -> (r -> r -> r) -> (s -> Type a -> (s, r)) -> Type a -> r+everythingWithContextOnTypes s0 r0 (<+>) f = go' s0 where+ go' s t = let (s', r) = f s t in r <+> go s' t+ go s (TypeApp _ t1 t2) = go' s t1 <+> go' s t2+ go s (KindApp _ t1 t2) = go' s t1 <+> go' s t2+ go s (ForAll _ _ (Just k) ty _) = go' s k <+> go' s ty+ go s (ForAll _ _ _ ty _) = go' s ty+ go s (ConstrainedType _ c ty) = foldl (<+>) r0 (map (go' s) (constraintKindArgs c) ++ map (go' s) (constraintArgs c)) <+> go' s ty+ go s (RCons _ _ ty rest) = go' s ty <+> go' s rest+ go s (KindedType _ ty k) = go' s ty <+> go' s k+ go s (BinaryNoParensType _ t1 t2 t3) = go' s t1 <+> go' s t2 <+> go' s t3+ go s (ParensInType _ t1) = go' s t1+ go _ _ = r0++annForType :: Lens' (Type a) a+annForType k (TUnknown a b) = (\z -> TUnknown z b) <$> k a+annForType k (TypeVar a b) = (\z -> TypeVar z b) <$> k a+annForType k (TypeLevelString a b) = (\z -> TypeLevelString z b) <$> k a+annForType k (TypeWildcard a b) = (\z -> TypeWildcard z b) <$> k a+annForType k (TypeConstructor a b) = (\z -> TypeConstructor z b) <$> k a+annForType k (TypeOp a b) = (\z -> TypeOp z b) <$> k a+annForType k (TypeApp a b c) = (\z -> TypeApp z b c) <$> k a+annForType k (KindApp a b c) = (\z -> KindApp z b c) <$> k a+annForType k (ForAll a b c d e) = (\z -> ForAll z b c d e) <$> k a+annForType k (ConstrainedType a b c) = (\z -> ConstrainedType z b c) <$> k a+annForType k (Skolem a b c d e) = (\z -> Skolem z b c d e) <$> k a+annForType k (REmpty a) = REmpty <$> k a+annForType k (RCons a b c d) = (\z -> RCons z b c d) <$> k a+annForType k (KindedType a b c) = (\z -> KindedType z b c) <$> k a+annForType k (BinaryNoParensType a b c d) = (\z -> BinaryNoParensType z b c d) <$> k a+annForType k (ParensInType a b) = (\z -> ParensInType z b) <$> k a++getAnnForType :: Type a -> a+getAnnForType = (^. annForType)++setAnnForType :: a -> Type a -> Type a+setAnnForType = set annForType++instance Eq (Type a) where+ (==) = eqType++instance Ord (Type a) where+ compare = compareType++eqType :: Type a -> Type b -> Bool+eqType (TUnknown _ a) (TUnknown _ a') = a == a'+eqType (TypeVar _ a) (TypeVar _ a') = a == a'+eqType (TypeLevelString _ a) (TypeLevelString _ a') = a == a'+eqType (TypeWildcard _ a) (TypeWildcard _ a') = a == a'+eqType (TypeConstructor _ a) (TypeConstructor _ a') = a == a'+eqType (TypeOp _ a) (TypeOp _ a') = a == a'+eqType (TypeApp _ a b) (TypeApp _ a' b') = eqType a a' && eqType b b'+eqType (KindApp _ a b) (KindApp _ a' b') = eqType a a' && eqType b b'+eqType (ForAll _ a b c d) (ForAll _ a' b' c' d') = a == a' && eqMaybeType b b' && eqType c c' && d == d'+eqType (ConstrainedType _ a b) (ConstrainedType _ a' b') = eqConstraint a a' && eqType b b'+eqType (Skolem _ a b c d) (Skolem _ a' b' c' d') = a == a' && eqMaybeType b b' && c == c' && d == d'+eqType (REmpty _) (REmpty _) = True+eqType (RCons _ a b c) (RCons _ a' b' c') = a == a' && eqType b b' && eqType c c'+eqType (KindedType _ a b) (KindedType _ a' b') = eqType a a' && eqType b b'+eqType (BinaryNoParensType _ a b c) (BinaryNoParensType _ a' b' c') = eqType a a' && eqType b b' && eqType c c'+eqType (ParensInType _ a) (ParensInType _ a') = eqType a a'+eqType _ _ = False++eqMaybeType :: Maybe (Type a) -> Maybe (Type b) -> Bool+eqMaybeType (Just a) (Just b) = eqType a b+eqMaybeType Nothing Nothing = True+eqMaybeType _ _ = False++compareType :: Type a -> Type b -> Ordering+compareType (TUnknown _ a) (TUnknown _ a') = compare a a'+compareType (TypeVar _ a) (TypeVar _ a') = compare a a'+compareType (TypeLevelString _ a) (TypeLevelString _ a') = compare a a'+compareType (TypeWildcard _ a) (TypeWildcard _ a') = compare a a'+compareType (TypeConstructor _ a) (TypeConstructor _ a') = compare a a'+compareType (TypeOp _ a) (TypeOp _ a') = compare a a'+compareType (TypeApp _ a b) (TypeApp _ a' b') = compareType a a' <> compareType b b'+compareType (KindApp _ a b) (KindApp _ a' b') = compareType a a' <> compareType b b'+compareType (ForAll _ a b c d) (ForAll _ a' b' c' d') = compare a a' <> compareMaybeType b b' <> compareType c c' <> compare d d'+compareType (ConstrainedType _ a b) (ConstrainedType _ a' b') = compareConstraint a a' <> compareType b b'+compareType (Skolem _ a b c d) (Skolem _ a' b' c' d') = compare a a' <> compareMaybeType b b' <> compare c c' <> compare d d'+compareType (REmpty _) (REmpty _) = EQ+compareType (RCons _ a b c) (RCons _ a' b' c') = compare a a' <> compareType b b' <> compareType c c'+compareType (KindedType _ a b) (KindedType _ a' b') = compareType a a' <> compareType b b'+compareType (BinaryNoParensType _ a b c) (BinaryNoParensType _ a' b' c') = compareType a a' <> compareType b b' <> compareType c c'+compareType (ParensInType _ a) (ParensInType _ a') = compareType a a'+compareType typ typ' =+ compare (orderOf typ) (orderOf typ')+ where+ orderOf :: Type a -> Int+ orderOf TUnknown{} = 0+ orderOf TypeVar{} = 1+ orderOf TypeLevelString{} = 2+ orderOf TypeWildcard{} = 3+ orderOf TypeConstructor{} = 4+ orderOf TypeOp{} = 5+ orderOf TypeApp{} = 6+ orderOf KindApp{} = 7+ orderOf ForAll{} = 8+ orderOf ConstrainedType{} = 9+ orderOf Skolem{} = 10+ orderOf REmpty{} = 11+ orderOf RCons{} = 12+ orderOf KindedType{} = 13+ orderOf BinaryNoParensType{} = 14+ orderOf ParensInType{} = 15++compareMaybeType :: Maybe (Type a) -> Maybe (Type b) -> Ordering+compareMaybeType (Just a) (Just b) = compareType a b+compareMaybeType Nothing Nothing = EQ+compareMaybeType Nothing _ = LT+compareMaybeType _ _ = GT++instance Eq (Constraint a) where+ (==) = eqConstraint++instance Ord (Constraint a) where+ compare = compareConstraint++eqConstraint :: Constraint a -> Constraint b -> Bool+eqConstraint (Constraint _ a b c d) (Constraint _ a' b' c' d') = a == a' && and (zipWith eqType b b') && and (zipWith eqType c c') && d == d'++compareConstraint :: Constraint a -> Constraint b -> Ordering+compareConstraint (Constraint _ a b c d) (Constraint _ a' b' c' d') = compare a a' <> fold (zipWith compareType b b') <> fold (zipWith compareType c c') <> compare d d'
− tests/Main.hs
@@ -1,28 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DoAndIfThenElse #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE TupleSections #-}--module Main (main) where--import Prelude.Compat--import Test.Tasty--import qualified TestCst--import System.IO (hSetEncoding, stdout, stderr, utf8)--main :: IO ()-main = do- hSetEncoding stdout utf8- hSetEncoding stderr utf8-- cstTests <- TestCst.main-- defaultMain $- testGroup- "Tests"- [ cstTests- ]
− tests/TestCst.hs
@@ -1,227 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PackageImports #-}-module TestCst where--import Prelude--import Control.Monad (when)-import qualified Data.ByteString.Lazy as BS-import Data.Maybe (fromMaybe)-import Data.Text (Text)-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text-import qualified Data.Text.IO as Text-import Test.Tasty (TestTree, testGroup)-import Test.Tasty.Golden (goldenVsString, findByExtension)-import Test.Tasty.QuickCheck-import Text.Read (readMaybe)-import Language.PureScript.CST.Errors as CST-import Language.PureScript.CST.Lexer as CST-import Language.PureScript.CST.Print as CST-import Language.PureScript.CST.Types-import System.FilePath (takeBaseName, replaceExtension)--main :: IO TestTree-main = do- lytTests <- layoutTests- pure $ testGroup "cst"- [ lytTests- , litTests- ]--layoutTests :: IO TestTree-layoutTests = do- pursFiles <- findByExtension [".purs"] "./tests/purs/layout"- return $ testGroup "Layout golden tests" $ do- file <- pursFiles- pure $ goldenVsString- (takeBaseName file)- (replaceExtension file ".out")- (BS.fromStrict . Text.encodeUtf8 <$> runLexer file)- where- runLexer file = do- src <- Text.readFile file- case sequence $ CST.lex src of- Left (_, err) ->- pure $ Text.pack $ CST.prettyPrintError err- Right toks -> do- pure $ CST.printTokens toks--litTests :: TestTree-litTests = testGroup "Literals"- [ testProperty "Integer" $- checkTok checkReadNum (\case TokInt _ a -> Just a; _ -> Nothing) . unInt- , testProperty "Hex" $- checkTok checkReadNum (\case TokInt _ a -> Just a; _ -> Nothing) . unHex- , testProperty "Number" $- checkTok checkReadNum (\case TokNumber _ a -> Just a; _ -> Nothing) . unFloat- , testProperty "Exponent" $- checkTok checkReadNum (\case TokNumber _ a -> Just a; _ -> Nothing) . unExponent-- , testProperty "Integer (round trip)" $ roundTripTok . unInt- , testProperty "Hex (round trip)" $ roundTripTok . unHex- , testProperty "Number (round trip)" $ roundTripTok . unFloat- , testProperty "Exponent (round trip)" $ roundTripTok . unExponent- , testProperty "Char (round trip)" $ roundTripTok . unChar- , testProperty "String (round trip)" $ roundTripTok . unString- , testProperty "Raw String (round trip)" $ roundTripTok . unRawString- ]--readTok' :: String -> Text -> Gen SourceToken-readTok' failMsg t = case CST.lex t of- Right tok : _ ->- pure tok- Left (_, err) : _ ->- error $ failMsg <> ": " <> CST.prettyPrintError err- [] ->- error "Empty token stream"--readTok :: Text -> Gen SourceToken-readTok = readTok' "Failed to parse"--checkTok- :: (Text -> a -> Gen Bool)- -> (Token -> Maybe a)- -> Text- -> Gen Bool-checkTok p f t = do- SourceToken _ tok <- readTok t- case f tok of- Just a -> p t a- Nothing -> error $ "Failed to lex correctly: " <> show tok--roundTripTok :: Text -> Gen Bool-roundTripTok t = do- tok <- readTok t- let t' = CST.printTokens [tok]- tok' <- readTok' "Failed to re-parse" t'- pure $ tok == tok'--checkReadNum :: (Eq a, Read a) => Text -> a -> Gen Bool-checkReadNum t a = do- let- chs = case Text.unpack $ Text.replace ".e" ".0e" $ Text.replace "_" "" t of- chs' | last chs' == '.' -> chs' <> "0"- chs' -> chs'- case (== a) <$> readMaybe chs of- Just a' -> pure a'- Nothing -> error "Failed to `read`"--newtype PSSourceInt = PSSourceInt { unInt :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceInt where- arbitrary = resize 16 genInt--newtype PSSourceFloat = PSSourceFloat { unFloat :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceFloat where- arbitrary = resize 16 genFloat--newtype PSSourceExponent = PSSourceExponent { unExponent :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceExponent where- arbitrary = PSSourceExponent <$> do- floatPart <- unFloat <$> resize 5 genFloat- signPart <- fromMaybe "" <$> elements [ Just "+", Just "-", Nothing ]- expPart <- unInt <$> resize 1 genInt- pure $ floatPart <> "e" <> signPart <> expPart--newtype PSSourceHex = PSSourceHex { unHex :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceHex where- arbitrary = resize 16 genHex--newtype PSSourceChar = PSSourceChar { unChar :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceChar where- arbitrary = genChar--newtype PSSourceString = PSSourceString { unString :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceString where- arbitrary = resize 256 genString--newtype PSSourceRawString = PSSourceRawString { unRawString :: Text }- deriving (Show, Eq)--instance Arbitrary PSSourceRawString where- arbitrary = resize 256 genRawString--genInt :: Gen PSSourceInt-genInt = PSSourceInt . Text.pack <$> do- (:) <$> nonZeroChar- <*> listOf numChar--genFloat :: Gen PSSourceFloat-genFloat = PSSourceFloat <$> do- intPart <- unInt <$> genInt- floatPart <- Text.pack <$> listOf1 numChar- pure $ intPart <> "." <> floatPart--genHex :: Gen PSSourceHex-genHex = PSSourceHex <$> do- nums <- listOf1 hexDigit- pure $ "0x" <> Text.pack nums--genChar :: Gen PSSourceChar-genChar = PSSourceChar <$> do- ch <- resize 0xFFFF arbitrarySizedNatural >>= (genStringChar '\'' . toEnum)- pure $ "'" <> ch <> "'"--genString :: Gen PSSourceString-genString = PSSourceString <$> do- chs <- listOf $ arbitraryUnicodeChar >>= genStringChar '"'- pure $ "\"" <> Text.concat chs <> "\""--genStringChar :: Char -> Char -> Gen Text-genStringChar delimiter ch = frequency- [ (1, genCharEscape)- , (10, if ch `elem` [delimiter, '\n', '\r', '\\']- then discard- else pure $ Text.singleton ch- )- ]--genRawString :: Gen PSSourceRawString-genRawString = PSSourceRawString <$> do- chs <- listOf $ arbitraryUnicodeChar- let- k1 acc qs cs = do- let (cs', q) = span (/= '"') cs- k2 (acc <> cs') qs q- k2 acc qs [] = acc <> qs- k2 acc qs cs = do- let (q, cs') = span (== '"') cs- k1 (acc <> take 2 q) (qs <> drop 2 q) cs'- chs' = k1 [] [] chs- when (all (== '"') chs') discard- pure $ "\"\"\"" <> Text.pack chs' <> "\"\"\""--genCharEscape :: Gen Text-genCharEscape = oneof- [ pure "\\t"- , pure "\\r"- , pure "\\n"- , pure "\\\""- , pure "\\'"- , pure "\\\\"- , do- chs <- resize 4 $ listOf1 hexDigit- pure $ "\\x" <> Text.pack chs- ]--numChar :: Gen Char-numChar = elements "0123456789_"--nonZeroChar :: Gen Char-nonZeroChar = elements "123456789"--hexDigit :: Gen Char-hexDigit = elements $ ['a'..'f'] <> ['A'..'F'] <> ['0'..'9']
− tests/purs/layout/AdoIn.out
@@ -1,20 +0,0 @@-module Test where{--test = ado{- baz;- let {foo = bar}}- in bar;--test = ado {}in foo;--test = ado{- foo <- bar $ let {a = 42 }in a;- baz <- b}- in bar;--test = ado{- foo;- let {bar = let {a = 42 }in a};- let {baz = 42}}- in bar}-<eof>
− tests/purs/layout/AdoIn.purs
@@ -1,19 +0,0 @@-module Test where--test = ado- baz- let foo = bar- in bar--test = ado in foo--test = ado- foo <- bar $ let a = 42 in a- baz <- b- in bar--test = ado- foo- let bar = let a = 42 in a- let baz = 42- in bar
− tests/purs/layout/CaseGuards.out
@@ -1,54 +0,0 @@-module Test where{---- Including data because of `|` masking-data Foo- = Foo- | Bar- | Baz;--test =- case foo of{- a | b, c ->- d;- a | b, c -> d};--test = case a, b of{- c, d- | e ->- case e of{- f | true -> bar- | false -> baz}- | f -> g};--test a- | false =- case false of{- true | a > 12 -> true}- | otherwise = true;--test = case a of {foo | foo \a -> a -> true};--test = a `case _ of {x | unit # \_ -> true, true -> const}` b;--test = case a of{- 12 | do {that;- that }-> this- | otherwise -> this};--test a b = [ case _ of{- 12 | case a, b of{- _, 42 -> b;- _, 12 -> false}, b -> true- | case a, b of{- _, 42 -> b;- _, 12 -> false}, b -> true}, false ];--test a- | case a, b of{- _, 42 -> b;- _, 12 -> false}, b = true- | case a, b of{- _, 42 -> b;- _, 12 -> false}, b = true}--<eof>
− tests/purs/layout/CaseGuards.purs
@@ -1,53 +0,0 @@-module Test where---- Including data because of `|` masking-data Foo- = Foo- | Bar- | Baz--test =- case foo of- a | b, c ->- d- a | b, c -> d--test = case a, b of- c, d- | e ->- case e of- f | true -> bar- | false -> baz- | f -> g--test a- | false =- case false of- true | a > 12 -> true- | otherwise = true--test = case a of foo | foo \a -> a -> true--test = a `case _ of x | unit # \_ -> true, true -> const` b--test = case a of- 12 | do that- that -> this- | otherwise -> this--test a b = [ case _ of- 12 | case a, b of- _, 42 -> b- _, 12 -> false, b -> true- | case a, b of- _, 42 -> b- _, 12 -> false, b -> true, false ]--test a- | case a, b of- _, 42 -> b- _, 12 -> false, b = true- | case a, b of- _, 42 -> b- _, 12 -> false, b = true-
− tests/purs/layout/CaseWhere.out
@@ -1,13 +0,0 @@-module Test where{--test = case foo of{- Nothing -> a- where {a = 12};- Just a -> do{- what}}- where{- foo = bar};--test = case f of {Foo -> do {that}- where {foo = 12}}}-<eof>
− tests/purs/layout/CaseWhere.purs
@@ -1,12 +0,0 @@-module Test where--test = case foo of- Nothing -> a- where a = 12- Just a -> do- what- where- foo = bar--test = case f of Foo -> do that- where foo = 12
− tests/purs/layout/ClassHead.out
@@ -1,11 +0,0 @@-module Test where{--import Foo (class Foo);--class Foo a b c d | a -> b, c -> d where{- foo :: Foo};--class Foo a b c d | a -> b, c -> d;--instance foo :: Foo}-<eof>
− tests/purs/layout/ClassHead.purs
@@ -1,10 +0,0 @@-module Test where--import Foo (class Foo)--class Foo a b c d | a -> b, c -> d where- foo :: Foo--class Foo a b c d | a -> b, c -> d--instance foo :: Foo
− tests/purs/layout/Commas.out
@@ -1,23 +0,0 @@-module Test where{--test =- [ case do {foo}, bar of{- a | b, c -> d}, bar- ];--test =- [ case do {foo}, bar of {a | b, c -> d}, bar ];--test =- [ do {do {do {foo}}}, bar ];--test =- [ \foo -> foo, bar ];--test = foo where{- bar =- case a, b of{- c, d | d == [case true, w of {1, a -> true}, false ] -> d;- e, d | do {what}, do {that }-> d}}}--<eof>
− tests/purs/layout/Commas.purs
@@ -1,22 +0,0 @@-module Test where--test =- [ case do foo, bar of- a | b, c -> d, bar- ]--test =- [ case do foo, bar of a | b, c -> d, bar ]--test =- [ do do do foo, bar ]--test =- [ \foo -> foo, bar ]--test = foo where- bar =- case a, b of- c, d | d == [case true, w of 1, a -> true, false ] -> d- e, d | do what, do that -> d-
− tests/purs/layout/Delimiter.out
@@ -1,14 +0,0 @@-module Test where{--test1 = a;-test2 = {- b-};-test3 = do{- foo;- bar (- baz- ) == 12;- baz};-test4 = c}-<eof>
− tests/purs/layout/Delimiter.purs
@@ -1,13 +0,0 @@-module Test where--test1 = a-test2 = {- b-}-test3 = do- foo- bar (- baz- ) == 12- baz-test4 = c
− tests/purs/layout/DoLet.out
@@ -1,16 +0,0 @@-module Test where{--test = do{- let {foo = bar};- foo};--test = do{- let {foo = bar};- in baz;- foo};--test = do{- let {foo = bar}- in baz;- foo}}-<eof>
− tests/purs/layout/DoLet.purs
@@ -1,15 +0,0 @@-module Test where--test = do- let foo = bar- foo--test = do- let foo = bar- in baz- foo--test = do- let foo = bar- in baz- foo
− tests/purs/layout/DoOperator.out
@@ -1,9 +0,0 @@-module Test where{--test = do{- foo;- foo do{- bar}}- <|> bar}--<eof>
− tests/purs/layout/DoOperator.purs
@@ -1,8 +0,0 @@-module Test where--test = do- foo- foo do- bar- <|> bar-
− tests/purs/layout/DoWhere.out
@@ -1,7 +0,0 @@-module Test where{--test =- do{- do {do{- foo }}}where {bar = baz}}-<eof>
− tests/purs/layout/DoWhere.purs
@@ -1,6 +0,0 @@-module Test where--test =- do- do do- foo where bar = baz
− tests/purs/layout/IfThenElseDo.out
@@ -1,11 +0,0 @@-module Test where{--foo = do{- if true then- false- else if false then do{- that}- else do{- what};- that}}-<eof>
− tests/purs/layout/IfThenElseDo.purs
@@ -1,10 +0,0 @@-module Test where--foo = do- if true then- false- else if false then do- that- else do- what- that
− tests/purs/layout/InstanceChainElse.out
@@ -1,5 +0,0 @@-module Test where{--instance foo :: Foo Int else bar :: Foo String-else baz :: Foo Boolean}-<eof>
− tests/purs/layout/InstanceChainElse.purs
@@ -1,4 +0,0 @@-module Test where--instance foo :: Foo Int else bar :: Foo String-else baz :: Foo Boolean
− tests/purs/layout/LetGuards.out
@@ -1,30 +0,0 @@-module Test where{--test =- let{- foo- | bar- , baz =- 42- | otherwise = 100}- in- foo;--test = do{- let{- foo- | bar- , baz =- 42- | otherwise = 100};- foo};--test = ado{- let{- foo- | bar- , baz =- 42- | otherwise = 100};- foo}}-<eof>
− tests/purs/layout/LetGuards.purs
@@ -1,29 +0,0 @@-module Test where--test =- let- foo- | bar- , baz =- 42- | otherwise = 100- in- foo--test = do- let- foo- | bar- , baz =- 42- | otherwise = 100- foo--test = ado- let- foo- | bar- , baz =- 42- | otherwise = 100- foo