purescript 0.10.7 → 0.11.0
raw patch · 230 files changed
+7854/−6248 lines, 230 filesdep +gitrevdep −aeson-prettydep −foldldep −system-filepathdep ~Globdep ~aesondep ~basenew-component:exe:pursPVP ok
version bump matches the API change (PVP)
Dependencies added: gitrev
Dependencies removed: aeson-pretty, foldl, system-filepath, turtle
Dependency ranges changed: Glob, aeson, base, blaze-html, directory, http-client, mtl, optparse-applicative, parsec, pipes, process, stm, transformers, transformers-compat, websockets
API changes (from Hackage documentation)
- Language.PureScript.AST.Declarations: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.AST.Declarations.DeclarationRef
- Language.PureScript.AST.Declarations: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.AST.Declarations.ImportDeclarationType
- Language.PureScript.AST.Declarations: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.Declarations.DeclarationRef
- Language.PureScript.AST.Declarations: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.Declarations.ImportDeclarationType
- Language.PureScript.AST.Declarations: type Guard = Expr
- Language.PureScript.AST.Operators: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.AST.Operators.Associativity
- Language.PureScript.AST.Operators: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.Operators.Associativity
- Language.PureScript.AST.Operators: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.Operators.Fixity
- Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.AST.SourcePos.SourcePos
- Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.AST.SourcePos.SourceSpan
- Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.SourcePos.SourcePos
- Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.AST.SourcePos.SourceSpan
- Language.PureScript.CodeGen.JS.AST: Add :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: And :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: BitwiseAnd :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: BitwiseNot :: UnaryOperator
- Language.PureScript.CodeGen.JS.AST: BitwiseOr :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: BitwiseXor :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Divide :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: EqualTo :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: GreaterThan :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: GreaterThanOrEqualTo :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: JSApp :: (Maybe SourceSpan) -> JS -> [JS] -> JS
- Language.PureScript.CodeGen.JS.AST: JSArrayLiteral :: (Maybe SourceSpan) -> [JS] -> JS
- Language.PureScript.CodeGen.JS.AST: JSAssignment :: (Maybe SourceSpan) -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSBinary :: (Maybe SourceSpan) -> BinaryOperator -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSBlock :: (Maybe SourceSpan) -> [JS] -> JS
- Language.PureScript.CodeGen.JS.AST: JSBooleanLiteral :: (Maybe SourceSpan) -> Bool -> JS
- Language.PureScript.CodeGen.JS.AST: JSBreak :: (Maybe SourceSpan) -> Text -> JS
- Language.PureScript.CodeGen.JS.AST: JSComment :: (Maybe SourceSpan) -> [Comment] -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSConditional :: (Maybe SourceSpan) -> JS -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSContinue :: (Maybe SourceSpan) -> Text -> JS
- Language.PureScript.CodeGen.JS.AST: JSFor :: (Maybe SourceSpan) -> Text -> JS -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSForIn :: (Maybe SourceSpan) -> Text -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSFunction :: (Maybe SourceSpan) -> (Maybe Text) -> [Text] -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSIfElse :: (Maybe SourceSpan) -> JS -> JS -> (Maybe JS) -> JS
- Language.PureScript.CodeGen.JS.AST: JSIndexer :: (Maybe SourceSpan) -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSInstanceOf :: (Maybe SourceSpan) -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSLabel :: (Maybe SourceSpan) -> Text -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSNew :: UnaryOperator
- Language.PureScript.CodeGen.JS.AST: JSNumericLiteral :: (Maybe SourceSpan) -> (Either Integer Double) -> JS
- Language.PureScript.CodeGen.JS.AST: JSObjectLiteral :: (Maybe SourceSpan) -> [(PSString, JS)] -> JS
- Language.PureScript.CodeGen.JS.AST: JSRaw :: (Maybe SourceSpan) -> Text -> JS
- Language.PureScript.CodeGen.JS.AST: JSReturn :: (Maybe SourceSpan) -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSStringLiteral :: (Maybe SourceSpan) -> PSString -> JS
- Language.PureScript.CodeGen.JS.AST: JSThrow :: (Maybe SourceSpan) -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSTypeOf :: (Maybe SourceSpan) -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSUnary :: (Maybe SourceSpan) -> UnaryOperator -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: JSVar :: (Maybe SourceSpan) -> Text -> JS
- Language.PureScript.CodeGen.JS.AST: JSVariableIntroduction :: (Maybe SourceSpan) -> Text -> (Maybe JS) -> JS
- Language.PureScript.CodeGen.JS.AST: JSWhile :: (Maybe SourceSpan) -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: LessThan :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: LessThanOrEqualTo :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Modulus :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Multiply :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Negate :: UnaryOperator
- Language.PureScript.CodeGen.JS.AST: Not :: UnaryOperator
- Language.PureScript.CodeGen.JS.AST: NotEqualTo :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Or :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Positive :: UnaryOperator
- Language.PureScript.CodeGen.JS.AST: ShiftLeft :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: ShiftRight :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: Subtract :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: ZeroFillShiftRight :: BinaryOperator
- Language.PureScript.CodeGen.JS.AST: data BinaryOperator
- Language.PureScript.CodeGen.JS.AST: data JS
- Language.PureScript.CodeGen.JS.AST: data UnaryOperator
- Language.PureScript.CodeGen.JS.AST: everythingOnJS :: (r -> r -> r) -> (JS -> r) -> JS -> r
- Language.PureScript.CodeGen.JS.AST: everywhereOnJS :: (JS -> JS) -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: everywhereOnJSTopDown :: (JS -> JS) -> JS -> JS
- Language.PureScript.CodeGen.JS.AST: everywhereOnJSTopDownM :: (Monad m) => (JS -> m JS) -> JS -> m JS
- Language.PureScript.CodeGen.JS.AST: getSourceSpan :: JS -> Maybe SourceSpan
- Language.PureScript.CodeGen.JS.AST: instance GHC.Classes.Eq Language.PureScript.CodeGen.JS.AST.BinaryOperator
- Language.PureScript.CodeGen.JS.AST: instance GHC.Classes.Eq Language.PureScript.CodeGen.JS.AST.JS
- Language.PureScript.CodeGen.JS.AST: instance GHC.Classes.Eq Language.PureScript.CodeGen.JS.AST.UnaryOperator
- Language.PureScript.CodeGen.JS.AST: instance GHC.Show.Show Language.PureScript.CodeGen.JS.AST.BinaryOperator
- Language.PureScript.CodeGen.JS.AST: instance GHC.Show.Show Language.PureScript.CodeGen.JS.AST.JS
- Language.PureScript.CodeGen.JS.AST: instance GHC.Show.Show Language.PureScript.CodeGen.JS.AST.UnaryOperator
- Language.PureScript.CodeGen.JS.AST: withSourceSpan :: SourceSpan -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer: optimize :: (MonadReader Options m, MonadSupply m) => JS -> m JS
- Language.PureScript.CodeGen.JS.Optimizer.Blocks: collapseNestedBlocks :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Blocks: collapseNestedIfs :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Common: applyAll :: [a -> a] -> a -> a
- Language.PureScript.CodeGen.JS.Optimizer.Common: isDict :: (Text, PSString) -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: isDict' :: [(Text, PSString)] -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: isReassigned :: Text -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: isRebound :: JS -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: isUpdated :: Text -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: isUsed :: Text -> JS -> Bool
- Language.PureScript.CodeGen.JS.Optimizer.Common: removeFromBlock :: ([JS] -> [JS]) -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Common: replaceIdent :: Text -> JS -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Common: replaceIdents :: [(Text, JS)] -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Common: targetVariable :: JS -> Text
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: etaConvert :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: evaluateIifes :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: inlineCommonOperators :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: inlineCommonValues :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: inlineFnComposition :: forall m. MonadSupply m => JS -> m JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: inlineUnsafePartial :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: inlineVariables :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Inliner: unThunk :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.MagicDo: magicDo :: Options -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.TCO: tco :: Options -> JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Unused: removeCodeAfterReturnStatements :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Unused: removeUndefinedApp :: JS -> JS
- Language.PureScript.CodeGen.JS.Optimizer.Unused: removeUnusedArg :: JS -> JS
- Language.PureScript.Comments: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Comments.Comment
- Language.PureScript.Comments: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Comments.Comment
- Language.PureScript.Constants: __superclass_ :: forall a. (IsString a) => a
- Language.PureScript.Constants: effect :: forall a. (IsString a) => a
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Docs.RenderedCode.Types.ContainingModule
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Docs.RenderedCode.Types.Link
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Docs.RenderedCode.Types.Namespace
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.RenderedCode.Types.ContainingModule
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.RenderedCode.Types.Link
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.RenderedCode.Types.Namespace
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.RenderedCode.Types.RenderedCode
- Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.RenderedCode.Types.RenderedCodeElement
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Docs.Types.GithubUser
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Docs.Types.NotYetKnown
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.FromJSON a => Data.Aeson.Types.Class.FromJSON (Language.PureScript.Docs.Types.Package a)
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.ChildDeclaration
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.ChildDeclarationInfo
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.Declaration
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.DeclarationInfo
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.GithubRepo
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.GithubUser
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.Module
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Docs.Types.NotYetKnown
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON a => Data.Aeson.Types.Class.ToJSON (Language.PureScript.Docs.Types.InPackage a)
- Language.PureScript.Docs.Types: instance Data.Aeson.Types.Class.ToJSON a => Data.Aeson.Types.Class.ToJSON (Language.PureScript.Docs.Types.Package a)
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Environment.DataDeclType
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Environment.FunctionalDependency
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Environment.TypeKind
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Environment.DataDeclType
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Environment.FunctionalDependency
- Language.PureScript.Environment: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Environment.TypeKind
- Language.PureScript.Environment: kindEffect :: Kind
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Errors.JSON.ErrorPosition
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Errors.JSON.ErrorSuggestion
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Errors.JSON.JSONError
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Errors.JSON.JSONResult
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Errors.JSON.ErrorPosition
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Errors.JSON.ErrorSuggestion
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Errors.JSON.JSONError
- Language.PureScript.Errors.JSON: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Errors.JSON.JSONResult
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Externs.ExternsDeclaration
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Externs.ExternsFile
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Externs.ExternsFixity
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Externs.ExternsImport
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Externs.ExternsTypeFixity
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Externs.ExternsDeclaration
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Externs.ExternsFile
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Externs.ExternsFixity
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Externs.ExternsImport
- Language.PureScript.Externs: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Externs.ExternsTypeFixity
- Language.PureScript.Ide.Command: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Command.Command
- Language.PureScript.Ide.Command: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Command.ImportCommand
- Language.PureScript.Ide.Command: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Command.ListType
- Language.PureScript.Ide.Error: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Ide.Error.IdeError
- Language.PureScript.Ide.Error: instance GHC.Classes.Eq Language.PureScript.Ide.Error.IdeError
- Language.PureScript.Ide.Filter: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Filter.Filter
- Language.PureScript.Ide.Matcher: instance Data.Aeson.Types.Class.FromJSON (Language.PureScript.Ide.Matcher.Matcher Language.PureScript.Ide.Types.IdeDeclarationAnn)
- Language.PureScript.Ide.SourceFile: getImportsForFile :: (MonadIO m, MonadError IdeError m) => FilePath -> m [ModuleImport]
- Language.PureScript.Ide.Types: ModuleImport :: ModuleIdent -> ImportDeclarationType -> Maybe Text -> ModuleImport
- Language.PureScript.Ide.Types: [annExportedFrom] :: Annotation -> Maybe ModuleName
- Language.PureScript.Ide.Types: [annLocation] :: Annotation -> Maybe SourceSpan
- Language.PureScript.Ide.Types: [annTypeAnnotation] :: Annotation -> Maybe Type
- Language.PureScript.Ide.Types: [importModuleName] :: ModuleImport -> ModuleIdent
- Language.PureScript.Ide.Types: [importQualifier] :: ModuleImport -> Maybe Text
- Language.PureScript.Ide.Types: [importType] :: ModuleImport -> ImportDeclarationType
- Language.PureScript.Ide.Types: data ModuleImport
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Types.PursuitQuery
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Types.PursuitResponse
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Ide.Types.PursuitSearchType
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Ide.Types.Completion
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Ide.Types.ModuleImport
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Ide.Types.PursuitResponse
- Language.PureScript.Ide.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Ide.Types.Success
- Language.PureScript.Ide.Types: instance GHC.Classes.Eq Language.PureScript.Ide.Types.ModuleImport
- Language.PureScript.Ide.Types: instance GHC.Classes.Eq Language.PureScript.Ide.Types.Success
- Language.PureScript.Ide.Types: instance GHC.Show.Show Language.PureScript.Ide.Types.ModuleImport
- Language.PureScript.Ide.Util: prettyTypeT :: Type -> Text
- Language.PureScript.Interactive.Types: Reset :: Directive
- Language.PureScript.Interactive.Types: ResetState :: Command
- Language.PureScript.Kinds: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Kinds.Kind
- Language.PureScript.Kinds: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Kinds.Kind
- Language.PureScript.Label: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Label.Label
- Language.PureScript.Label: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Label.Label
- Language.PureScript.Names: instance Data.Aeson.Types.Class.FromJSON (Language.PureScript.Names.OpName a)
- Language.PureScript.Names: instance Data.Aeson.Types.Class.FromJSON (Language.PureScript.Names.ProperName a)
- Language.PureScript.Names: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Names.Ident
- Language.PureScript.Names: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Names.ModuleName
- Language.PureScript.Names: instance Data.Aeson.Types.Class.FromJSON a0 => Data.Aeson.Types.Class.FromJSON (Language.PureScript.Names.Qualified a0)
- Language.PureScript.Names: instance Data.Aeson.Types.Class.ToJSON (Language.PureScript.Names.OpName a)
- Language.PureScript.Names: instance Data.Aeson.Types.Class.ToJSON (Language.PureScript.Names.ProperName a)
- Language.PureScript.Names: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Names.Ident
- Language.PureScript.Names: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Names.ModuleName
- Language.PureScript.Names: instance Data.Aeson.Types.Class.ToJSON a0 => Data.Aeson.Types.Class.ToJSON (Language.PureScript.Names.Qualified a0)
- Language.PureScript.Options: [optionsMain] :: Options -> Maybe String
- Language.PureScript.Options: [optionsNoMagicDo] :: Options -> Bool
- Language.PureScript.Options: [optionsNoOptimizations] :: Options -> Bool
- Language.PureScript.Options: [optionsNoTco] :: Options -> Bool
- Language.PureScript.PSString: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.PSString.PSString
- Language.PureScript.PSString: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.PSString.PSString
- Language.PureScript.Pretty.JS: prettyPrintJS :: [JS] -> Text
- Language.PureScript.Pretty.JS: prettyPrintJSWithSourceMaps :: [JS] -> (Text, [SMap])
- Language.PureScript.Publish: getBowerRepositoryInfo :: PackageMeta -> PrepareM (GithubUser, GithubRepo)
- Language.PureScript.Publish.ErrorsWarnings: BowerExecutableNotFound :: [String] -> UserError
- Language.PureScript.Publish.ErrorsWarnings: BowerJSONNotFound :: UserError
- Language.PureScript.Publish.ErrorsWarnings: CouldntDecodeBowerJSON :: (ParseError BowerError) -> UserError
- Language.PureScript.Publish.ErrorsWarnings: FromBowerList :: JSONSource
- Language.PureScript.Publish.Utils: purescriptDepsFiles :: Pattern
- Language.PureScript.TypeChecker.Rows: checkDuplicateLabels :: forall m. (MonadError MultipleErrors m) => Expr -> m ()
- Language.PureScript.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Types.Constraint
- Language.PureScript.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Types.ConstraintData
- Language.PureScript.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Types.SkolemScope
- Language.PureScript.Types: instance Data.Aeson.Types.Class.FromJSON Language.PureScript.Types.Type
- Language.PureScript.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Types.Constraint
- Language.PureScript.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Types.ConstraintData
- Language.PureScript.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Types.SkolemScope
- Language.PureScript.Types: instance Data.Aeson.Types.Class.ToJSON Language.PureScript.Types.Type
+ Language.PureScript.AST.Binders: instance GHC.Classes.Ord Language.PureScript.AST.Binders.Binder
+ Language.PureScript.AST.Binders: isIrrefutable :: Binder -> Bool
+ Language.PureScript.AST.Declarations: BoundValueDeclaration :: Binder -> Expr -> Declaration
+ Language.PureScript.AST.Declarations: ConditionGuard :: Expr -> Guard
+ Language.PureScript.AST.Declarations: ExpectedTypeConstructor :: (Qualified (ProperName ClassName)) -> [Type] -> Type -> SimpleErrorMessage
+ Language.PureScript.AST.Declarations: GuardedExpr :: [Guard] -> Expr -> GuardedExpr
+ Language.PureScript.AST.Declarations: InvalidDerivedInstance :: (Qualified (ProperName ClassName)) -> [Type] -> Int -> SimpleErrorMessage
+ Language.PureScript.AST.Declarations: PatternGuard :: Binder -> Expr -> Guard
+ Language.PureScript.AST.Declarations: UnusableDeclaration :: Ident -> SimpleErrorMessage
+ Language.PureScript.AST.Declarations: [tsAfterIdentifiers] :: TypeSearch -> [(Qualified Text, Type)]
+ Language.PureScript.AST.Declarations: [tsAfterRecordFields] :: TypeSearch -> Maybe [(Label, Type)]
+ Language.PureScript.AST.Declarations: data Guard
+ Language.PureScript.AST.Declarations: data GuardedExpr
+ Language.PureScript.AST.Declarations: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.AST.Declarations.DeclarationRef
+ Language.PureScript.AST.Declarations: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.AST.Declarations.ImportDeclarationType
+ Language.PureScript.AST.Declarations: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.Declarations.DeclarationRef
+ Language.PureScript.AST.Declarations: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.Declarations.ImportDeclarationType
+ Language.PureScript.AST.Declarations: instance GHC.Show.Show Language.PureScript.AST.Declarations.Guard
+ Language.PureScript.AST.Declarations: instance GHC.Show.Show Language.PureScript.AST.Declarations.GuardedExpr
+ Language.PureScript.AST.Declarations: isTrueExpr :: Expr -> Bool
+ Language.PureScript.AST.Declarations: onTypeSearchTypes :: (Type -> Type) -> TypeSearch -> TypeSearch
+ Language.PureScript.AST.Declarations: onTypeSearchTypesM :: (Applicative m) => (Type -> m Type) -> TypeSearch -> m TypeSearch
+ Language.PureScript.AST.Operators: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.AST.Operators.Associativity
+ Language.PureScript.AST.Operators: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.Operators.Associativity
+ Language.PureScript.AST.Operators: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.Operators.Fixity
+ Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.AST.SourcePos.SourcePos
+ Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.AST.SourcePos.SourceSpan
+ Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.SourcePos.SourcePos
+ Language.PureScript.AST.SourcePos: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.AST.SourcePos.SourceSpan
+ Language.PureScript.AST.Traversals: guardedExprM :: Applicative m => (Guard -> m Guard) -> (Expr -> m Expr) -> GuardedExpr -> m GuardedExpr
+ Language.PureScript.AST.Traversals: mapGuardedExpr :: (Guard -> Guard) -> (Expr -> Expr) -> GuardedExpr -> GuardedExpr
+ Language.PureScript.CodeGen.JS.Printer: prettyPrintJS :: [AST] -> Text
+ Language.PureScript.CodeGen.JS.Printer: prettyPrintJSWithSourceMaps :: [AST] -> (Text, [SMap])
+ Language.PureScript.Comments: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Comments.Comment
+ Language.PureScript.Comments: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Comments.Comment
+ Language.PureScript.Constants: discard :: forall a. (IsString a) => a
+ Language.PureScript.Constants: discardUnitDictionary :: forall a. (IsString a) => a
+ Language.PureScript.CoreFn.Meta: instance GHC.Classes.Ord Language.PureScript.CoreFn.Meta.ConstructorType
+ Language.PureScript.CoreFn.Meta: instance GHC.Classes.Ord Language.PureScript.CoreFn.Meta.Meta
+ Language.PureScript.CoreImp.AST: Add :: BinaryOperator
+ Language.PureScript.CoreImp.AST: And :: BinaryOperator
+ Language.PureScript.CoreImp.AST: App :: (Maybe SourceSpan) -> AST -> [AST] -> AST
+ Language.PureScript.CoreImp.AST: ArrayLiteral :: (Maybe SourceSpan) -> [AST] -> AST
+ Language.PureScript.CoreImp.AST: Assignment :: (Maybe SourceSpan) -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: Binary :: (Maybe SourceSpan) -> BinaryOperator -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: BitwiseAnd :: BinaryOperator
+ Language.PureScript.CoreImp.AST: BitwiseNot :: UnaryOperator
+ Language.PureScript.CoreImp.AST: BitwiseOr :: BinaryOperator
+ Language.PureScript.CoreImp.AST: BitwiseXor :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Block :: (Maybe SourceSpan) -> [AST] -> AST
+ Language.PureScript.CoreImp.AST: BooleanLiteral :: (Maybe SourceSpan) -> Bool -> AST
+ Language.PureScript.CoreImp.AST: Comment :: (Maybe SourceSpan) -> [Comment] -> AST -> AST
+ Language.PureScript.CoreImp.AST: Divide :: BinaryOperator
+ Language.PureScript.CoreImp.AST: EqualTo :: BinaryOperator
+ Language.PureScript.CoreImp.AST: For :: (Maybe SourceSpan) -> Text -> AST -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: ForIn :: (Maybe SourceSpan) -> Text -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: Function :: (Maybe SourceSpan) -> (Maybe Text) -> [Text] -> AST -> AST
+ Language.PureScript.CoreImp.AST: GreaterThan :: BinaryOperator
+ Language.PureScript.CoreImp.AST: GreaterThanOrEqualTo :: BinaryOperator
+ Language.PureScript.CoreImp.AST: IfElse :: (Maybe SourceSpan) -> AST -> AST -> (Maybe AST) -> AST
+ Language.PureScript.CoreImp.AST: Indexer :: (Maybe SourceSpan) -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: InstanceOf :: (Maybe SourceSpan) -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: LessThan :: BinaryOperator
+ Language.PureScript.CoreImp.AST: LessThanOrEqualTo :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Modulus :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Multiply :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Negate :: UnaryOperator
+ Language.PureScript.CoreImp.AST: New :: UnaryOperator
+ Language.PureScript.CoreImp.AST: Not :: UnaryOperator
+ Language.PureScript.CoreImp.AST: NotEqualTo :: BinaryOperator
+ Language.PureScript.CoreImp.AST: NumericLiteral :: (Maybe SourceSpan) -> (Either Integer Double) -> AST
+ Language.PureScript.CoreImp.AST: ObjectLiteral :: (Maybe SourceSpan) -> [(PSString, AST)] -> AST
+ Language.PureScript.CoreImp.AST: Or :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Positive :: UnaryOperator
+ Language.PureScript.CoreImp.AST: Return :: (Maybe SourceSpan) -> AST -> AST
+ Language.PureScript.CoreImp.AST: ReturnNoResult :: (Maybe SourceSpan) -> AST
+ Language.PureScript.CoreImp.AST: ShiftLeft :: BinaryOperator
+ Language.PureScript.CoreImp.AST: ShiftRight :: BinaryOperator
+ Language.PureScript.CoreImp.AST: StringLiteral :: (Maybe SourceSpan) -> PSString -> AST
+ Language.PureScript.CoreImp.AST: Subtract :: BinaryOperator
+ Language.PureScript.CoreImp.AST: Throw :: (Maybe SourceSpan) -> AST -> AST
+ Language.PureScript.CoreImp.AST: Unary :: (Maybe SourceSpan) -> UnaryOperator -> AST -> AST
+ Language.PureScript.CoreImp.AST: Var :: (Maybe SourceSpan) -> Text -> AST
+ Language.PureScript.CoreImp.AST: VariableIntroduction :: (Maybe SourceSpan) -> Text -> (Maybe AST) -> AST
+ Language.PureScript.CoreImp.AST: While :: (Maybe SourceSpan) -> AST -> AST -> AST
+ Language.PureScript.CoreImp.AST: ZeroFillShiftRight :: BinaryOperator
+ Language.PureScript.CoreImp.AST: data AST
+ Language.PureScript.CoreImp.AST: data BinaryOperator
+ Language.PureScript.CoreImp.AST: data UnaryOperator
+ Language.PureScript.CoreImp.AST: everything :: (r -> r -> r) -> (AST -> r) -> AST -> r
+ Language.PureScript.CoreImp.AST: everywhere :: (AST -> AST) -> AST -> AST
+ Language.PureScript.CoreImp.AST: everywhereTopDown :: (AST -> AST) -> AST -> AST
+ Language.PureScript.CoreImp.AST: everywhereTopDownM :: (Monad m) => (AST -> m AST) -> AST -> m AST
+ Language.PureScript.CoreImp.AST: getSourceSpan :: AST -> Maybe SourceSpan
+ Language.PureScript.CoreImp.AST: instance GHC.Classes.Eq Language.PureScript.CoreImp.AST.AST
+ Language.PureScript.CoreImp.AST: instance GHC.Classes.Eq Language.PureScript.CoreImp.AST.BinaryOperator
+ Language.PureScript.CoreImp.AST: instance GHC.Classes.Eq Language.PureScript.CoreImp.AST.UnaryOperator
+ Language.PureScript.CoreImp.AST: instance GHC.Show.Show Language.PureScript.CoreImp.AST.AST
+ Language.PureScript.CoreImp.AST: instance GHC.Show.Show Language.PureScript.CoreImp.AST.BinaryOperator
+ Language.PureScript.CoreImp.AST: instance GHC.Show.Show Language.PureScript.CoreImp.AST.UnaryOperator
+ Language.PureScript.CoreImp.AST: withSourceSpan :: SourceSpan -> AST -> AST
+ Language.PureScript.CoreImp.Optimizer: optimize :: MonadSupply m => AST -> m AST
+ Language.PureScript.CoreImp.Optimizer.Blocks: collapseNestedBlocks :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Blocks: collapseNestedIfs :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Common: applyAll :: [a -> a] -> a -> a
+ Language.PureScript.CoreImp.Optimizer.Common: isDict :: (Text, PSString) -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: isDict' :: [(Text, PSString)] -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: isReassigned :: Text -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: isRebound :: AST -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: isUpdated :: Text -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: isUsed :: Text -> AST -> Bool
+ Language.PureScript.CoreImp.Optimizer.Common: removeFromBlock :: ([AST] -> [AST]) -> AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Common: replaceIdent :: Text -> AST -> AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Common: replaceIdents :: [(Text, AST)] -> AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Common: targetVariable :: AST -> Text
+ Language.PureScript.CoreImp.Optimizer.Inliner: etaConvert :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: evaluateIifes :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: inlineCommonOperators :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: inlineCommonValues :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: inlineFnComposition :: forall m. MonadSupply m => AST -> m AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: inlineUnsafePartial :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: inlineVariables :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Inliner: unThunk :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.MagicDo: magicDo :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.TCO: tco :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Unused: removeCodeAfterReturnStatements :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Unused: removeUndefinedApp :: AST -> AST
+ Language.PureScript.CoreImp.Optimizer.Unused: removeUnusedArg :: AST -> AST
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Docs.RenderedCode.Types.ContainingModule
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Docs.RenderedCode.Types.Link
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Docs.RenderedCode.Types.Namespace
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.RenderedCode.Types.ContainingModule
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.RenderedCode.Types.Link
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.RenderedCode.Types.Namespace
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.RenderedCode.Types.RenderedCode
+ Language.PureScript.Docs.RenderedCode.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.RenderedCode.Types.RenderedCodeElement
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Docs.Types.GithubUser
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Docs.Types.NotYetKnown
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Language.PureScript.Docs.Types.Package a)
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.ChildDeclaration
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.ChildDeclarationInfo
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.Declaration
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.DeclarationInfo
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.GithubRepo
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.GithubUser
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.Module
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Docs.Types.NotYetKnown
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Language.PureScript.Docs.Types.InPackage a)
+ Language.PureScript.Docs.Types: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Language.PureScript.Docs.Types.Package a)
+ Language.PureScript.Docs.Types: type ManifestError = BowerError
+ Language.PureScript.Environment: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Environment.DataDeclType
+ Language.PureScript.Environment: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Environment.FunctionalDependency
+ Language.PureScript.Environment: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Environment.TypeKind
+ Language.PureScript.Environment: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Environment.DataDeclType
+ Language.PureScript.Environment: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Environment.FunctionalDependency
+ Language.PureScript.Environment: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Environment.TypeKind
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Errors.JSON.ErrorPosition
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Errors.JSON.ErrorSuggestion
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Errors.JSON.JSONError
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Errors.JSON.JSONResult
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Errors.JSON.ErrorPosition
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Errors.JSON.ErrorSuggestion
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Errors.JSON.JSONError
+ Language.PureScript.Errors.JSON: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Errors.JSON.JSONResult
+ Language.PureScript.Externs: [efSourceSpan] :: ExternsFile -> SourceSpan
+ Language.PureScript.Externs: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Externs.ExternsDeclaration
+ Language.PureScript.Externs: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Externs.ExternsFile
+ Language.PureScript.Externs: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Externs.ExternsFixity
+ Language.PureScript.Externs: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Externs.ExternsImport
+ Language.PureScript.Externs: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Externs.ExternsTypeFixity
+ Language.PureScript.Externs: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Externs.ExternsDeclaration
+ Language.PureScript.Externs: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Externs.ExternsFile
+ Language.PureScript.Externs: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Externs.ExternsFixity
+ Language.PureScript.Externs: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Externs.ExternsImport
+ Language.PureScript.Externs: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Externs.ExternsTypeFixity
+ Language.PureScript.Ide.Command: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Command.Command
+ Language.PureScript.Ide.Command: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Command.ImportCommand
+ Language.PureScript.Ide.Command: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Command.ListType
+ Language.PureScript.Ide.Error: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Ide.Error.IdeError
+ Language.PureScript.Ide.Error: prettyPrintTypeSingleLine :: Type -> Text
+ Language.PureScript.Ide.Filter: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Filter.Filter
+ Language.PureScript.Ide.Imports: parseImportsFromFile :: (MonadIO m, MonadError IdeError m) => FilePath -> m (ModuleName, [(ModuleName, ImportDeclarationType, Maybe ModuleName)])
+ Language.PureScript.Ide.Matcher: instance Data.Aeson.Types.FromJSON.FromJSON (Language.PureScript.Ide.Matcher.Matcher Language.PureScript.Ide.Types.IdeDeclarationAnn)
+ Language.PureScript.Ide.Types: [_annExportedFrom] :: Annotation -> Maybe ModuleName
+ Language.PureScript.Ide.Types: [_annLocation] :: Annotation -> Maybe SourceSpan
+ Language.PureScript.Ide.Types: [_annTypeAnnotation] :: Annotation -> Maybe Type
+ Language.PureScript.Ide.Types: annExportedFrom :: Lens' Annotation (Maybe ModuleName)
+ Language.PureScript.Ide.Types: annLocation :: Lens' Annotation (Maybe SourceSpan)
+ Language.PureScript.Ide.Types: annTypeAnnotation :: Lens' Annotation (Maybe Type)
+ Language.PureScript.Ide.Types: encodeImport :: (ModuleName, ImportDeclarationType, Maybe ModuleName) -> Value
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Types.PursuitQuery
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Types.PursuitResponse
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Ide.Types.PursuitSearchType
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Ide.Types.Completion
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Ide.Types.PursuitResponse
+ Language.PureScript.Ide.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Ide.Types.Success
+ Language.PureScript.Ide.Types: instance GHC.Classes.Ord Language.PureScript.Ide.Types.Completion
+ Language.PureScript.Interactive.Message: guideURL :: String
+ Language.PureScript.Interactive.Message: noInputMessage :: String
+ Language.PureScript.Interactive.Types: Clear :: Directive
+ Language.PureScript.Interactive.Types: ClearState :: Command
+ Language.PureScript.Interactive.Types: Reload :: Directive
+ Language.PureScript.Interactive.Types: ReloadState :: Command
+ Language.PureScript.Interactive.Types: instance GHC.Show.Show Language.PureScript.Interactive.Types.Command
+ Language.PureScript.Kinds: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Kinds.Kind
+ Language.PureScript.Kinds: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Kinds.Kind
+ Language.PureScript.Label: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Label.Label
+ Language.PureScript.Label: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Label.Label
+ Language.PureScript.Names: instance Data.Aeson.Types.FromJSON.FromJSON (Language.PureScript.Names.OpName a)
+ Language.PureScript.Names: instance Data.Aeson.Types.FromJSON.FromJSON (Language.PureScript.Names.ProperName a)
+ Language.PureScript.Names: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Names.Ident
+ Language.PureScript.Names: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Names.ModuleName
+ Language.PureScript.Names: instance Data.Aeson.Types.FromJSON.FromJSON a0 => Data.Aeson.Types.FromJSON.FromJSON (Language.PureScript.Names.Qualified a0)
+ Language.PureScript.Names: instance Data.Aeson.Types.ToJSON.ToJSON (Language.PureScript.Names.OpName a)
+ Language.PureScript.Names: instance Data.Aeson.Types.ToJSON.ToJSON (Language.PureScript.Names.ProperName a)
+ Language.PureScript.Names: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Names.Ident
+ Language.PureScript.Names: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Names.ModuleName
+ Language.PureScript.Names: instance Data.Aeson.Types.ToJSON.ToJSON a0 => Data.Aeson.Types.ToJSON.ToJSON (Language.PureScript.Names.Qualified a0)
+ Language.PureScript.Names: instance GHC.Classes.Ord Language.PureScript.Names.Name
+ Language.PureScript.PSString: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.PSString.PSString
+ Language.PureScript.PSString: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.PSString.PSString
+ Language.PureScript.Parser.Declarations: parseDeclarationRef :: TokenParser DeclarationRef
+ Language.PureScript.Parser.Declarations: parseModuleDeclaration :: TokenParser (ModuleName, Maybe [DeclarationRef])
+ Language.PureScript.Parser.Lexer: lexLenient :: FilePath -> Text -> Either ParseError [PositionedToken]
+ Language.PureScript.Publish: getManifestRepositoryInfo :: PackageMeta -> PrepareM (GithubUser, GithubRepo)
+ Language.PureScript.Publish.ErrorsWarnings: CouldntDecodePackageManifest :: (ParseError ManifestError) -> UserError
+ Language.PureScript.Publish.ErrorsWarnings: FromResolutions :: JSONSource
+ Language.PureScript.Publish.ErrorsWarnings: MissingPath :: PackageName -> PackageWarning
+ Language.PureScript.Publish.ErrorsWarnings: PackageManifestNotFound :: UserError
+ Language.PureScript.Publish.ErrorsWarnings: ResolutionsFileNotFound :: UserError
+ Language.PureScript.Sugar.LetPattern: desugarLetPatternModule :: Module -> Module
+ Language.PureScript.TypeChecker.Entailment: instance GHC.Show.Show Language.PureScript.TypeChecker.Entailment.Evidence
+ Language.PureScript.TypeChecker.Entailment: instance GHC.Show.Show a => GHC.Show.Show (Language.PureScript.TypeChecker.Entailment.EntailsResult a)
+ Language.PureScript.TypeChecker.Monad: getHints :: MonadState CheckState m => m [ErrorMessageHint]
+ Language.PureScript.TypeChecker.Unify: alignRowsWith :: (Type -> Type -> a) -> Type -> Type -> ([a], (([(Label, Type)], Type), ([(Label, Type)], Type)))
+ Language.PureScript.TypeClassDictionaries: superclassName :: Qualified (ProperName ClassName) -> Integer -> Text
+ Language.PureScript.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Types.Constraint
+ Language.PureScript.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Types.ConstraintData
+ Language.PureScript.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Types.SkolemScope
+ Language.PureScript.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.PureScript.Types.Type
+ Language.PureScript.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Types.Constraint
+ Language.PureScript.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Types.ConstraintData
+ Language.PureScript.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Types.SkolemScope
+ Language.PureScript.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.PureScript.Types.Type
+ Language.PureScript.Types: rowToSortedList :: Type -> ([(Label, Type)], Type)
- Language.PureScript.AST.Declarations: Abs :: (Either Ident Binder) -> Expr -> Expr
+ Language.PureScript.AST.Declarations: Abs :: Binder -> Expr -> Expr
- Language.PureScript.AST.Declarations: CannotUseBindWithDo :: SimpleErrorMessage
+ Language.PureScript.AST.Declarations: CannotUseBindWithDo :: Ident -> SimpleErrorMessage
- Language.PureScript.AST.Declarations: CaseAlternative :: [Binder] -> Either [(Guard, Expr)] Expr -> CaseAlternative
+ Language.PureScript.AST.Declarations: CaseAlternative :: [Binder] -> [GuardedExpr] -> CaseAlternative
- Language.PureScript.AST.Declarations: EscapedSkolem :: (Maybe Expr) -> SimpleErrorMessage
+ Language.PureScript.AST.Declarations: EscapedSkolem :: Text -> (Maybe SourceSpan) -> Type -> SimpleErrorMessage
- Language.PureScript.AST.Declarations: TSAfter :: [(Qualified Ident, Type)] -> TypeSearch
+ Language.PureScript.AST.Declarations: TSAfter :: [(Qualified Text, Type)] -> Maybe [(Label, Type)] -> TypeSearch
- Language.PureScript.AST.Declarations: ValueDeclaration :: Ident -> NameKind -> [Binder] -> (Either [(Guard, Expr)] Expr) -> Declaration
+ Language.PureScript.AST.Declarations: ValueDeclaration :: Ident -> NameKind -> [Binder] -> [GuardedExpr] -> Declaration
- Language.PureScript.AST.Declarations: [caseAlternativeResult] :: CaseAlternative -> Either [(Guard, Expr)] Expr
+ Language.PureScript.AST.Declarations: [caseAlternativeResult] :: CaseAlternative -> [GuardedExpr]
- Language.PureScript.CodeGen.JS: moduleToJs :: forall m. (Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m) => Module Ann -> Maybe JS -> m [JS]
+ Language.PureScript.CodeGen.JS: moduleToJs :: forall m. (Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m) => Module Ann -> Maybe AST -> m [AST]
- Language.PureScript.Docs.AsHtml: HtmlRenderContext :: ModuleName -> (Namespace -> Text -> ContainingModule -> Maybe DocLink) -> (DocLink -> Text) -> (SourceSpan -> Text) -> HtmlRenderContext
+ Language.PureScript.Docs.AsHtml: HtmlRenderContext :: ModuleName -> (Namespace -> Text -> ContainingModule -> Maybe DocLink) -> (DocLink -> Text) -> (SourceSpan -> Maybe Text) -> HtmlRenderContext
- Language.PureScript.Docs.AsHtml: [renderSourceLink] :: HtmlRenderContext -> SourceSpan -> Text
+ Language.PureScript.Docs.AsHtml: [renderSourceLink] :: HtmlRenderContext -> SourceSpan -> Maybe Text
- Language.PureScript.Docs.Types: ErrorInPackageMeta :: BowerError -> PackageError
+ Language.PureScript.Docs.Types: ErrorInPackageMeta :: ManifestError -> PackageError
- Language.PureScript.Docs.Types: asInPackage :: Parse BowerError a -> Parse BowerError (InPackage a)
+ Language.PureScript.Docs.Types: asInPackage :: Parse ManifestError a -> Parse ManifestError (InPackage a)
- Language.PureScript.Docs.Types: bookmarksAsModuleMap :: Parse BowerError (Map ModuleName PackageName)
+ Language.PureScript.Docs.Types: bookmarksAsModuleMap :: Parse ManifestError (Map ModuleName PackageName)
- Language.PureScript.Externs: ExternsFile :: Text -> ModuleName -> [DeclarationRef] -> [ExternsImport] -> [ExternsFixity] -> [ExternsTypeFixity] -> [ExternsDeclaration] -> ExternsFile
+ Language.PureScript.Externs: ExternsFile :: Text -> ModuleName -> [DeclarationRef] -> [ExternsImport] -> [ExternsFixity] -> [ExternsTypeFixity] -> [ExternsDeclaration] -> SourceSpan -> ExternsFile
- Language.PureScript.Ide.Error: RebuildError :: [JSONError] -> IdeError
+ Language.PureScript.Ide.Error: RebuildError :: MultipleErrors -> IdeError
- Language.PureScript.Ide.Reexports: resolveReexports' :: ModuleMap [IdeDeclarationAnn] -> [IdeDeclarationAnn] -> [(ModuleName, DeclarationRef)] -> ReexportResult [IdeDeclarationAnn]
+ Language.PureScript.Ide.Reexports: resolveReexports' :: ModuleMap [IdeDeclarationAnn] -> [(ModuleName, DeclarationRef)] -> ReexportResult [IdeDeclarationAnn]
- Language.PureScript.Ide.Types: ImportList :: [ModuleImport] -> Success
+ Language.PureScript.Ide.Types: ImportList :: (ModuleName, [(ModuleName, ImportDeclarationType, Maybe ModuleName)]) -> Success
- Language.PureScript.Ide.Types: RebuildSuccess :: [JSONError] -> Success
+ Language.PureScript.Ide.Types: RebuildSuccess :: MultipleErrors -> Success
- Language.PureScript.Options: Options :: Bool -> Bool -> Maybe String -> Bool -> Bool -> Bool -> Bool -> Bool -> Options
+ Language.PureScript.Options: Options :: Bool -> Bool -> Bool -> Bool -> Options
- Language.PureScript.Parser.Declarations: parseGuard :: TokenParser Guard
+ Language.PureScript.Parser.Declarations: parseGuard :: TokenParser [Guard]
- Language.PureScript.Publish: getModules :: PrepareM ([Module], Map ModuleName PackageName)
+ Language.PureScript.Publish: getModules :: [(PackageName, FilePath)] -> PrepareM ([Module], Map ModuleName PackageName)
- Language.PureScript.Publish: getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]
+ Language.PureScript.Publish: getResolvedDependencies :: FilePath -> [PackageName] -> PrepareM [(PackageName, (FilePath, Version))]
- Language.PureScript.Publish: preparePackage :: PublishOptions -> IO (Either PackageError UploadedPackage)
+ Language.PureScript.Publish: preparePackage :: FilePath -> FilePath -> PublishOptions -> IO (Either PackageError UploadedPackage)
- Language.PureScript.Publish: preparePackage' :: PublishOptions -> PrepareM UploadedPackage
+ Language.PureScript.Publish: preparePackage' :: FilePath -> FilePath -> PublishOptions -> PrepareM UploadedPackage
- Language.PureScript.Publish: unsafePreparePackage :: PublishOptions -> IO UploadedPackage
+ Language.PureScript.Publish: unsafePreparePackage :: FilePath -> FilePath -> PublishOptions -> IO UploadedPackage
- Language.PureScript.Publish.ErrorsWarnings: JSONError :: JSONSource -> (ParseError BowerError) -> InternalError
+ Language.PureScript.Publish.ErrorsWarnings: JSONError :: JSONSource -> (ParseError ManifestError) -> InternalError
- Language.PureScript.TypeChecker.Skolems: introduceSkolemScope :: (MonadState CheckState m) => Type -> m Type
+ Language.PureScript.TypeChecker.Skolems: introduceSkolemScope :: MonadState CheckState m => Type -> m Type
- Language.PureScript.TypeChecker.Skolems: newSkolemConstant :: (MonadState CheckState m) => m Int
+ Language.PureScript.TypeChecker.Skolems: newSkolemConstant :: MonadState CheckState m => m Int
- Language.PureScript.TypeChecker.Skolems: newSkolemScope :: (MonadState CheckState m) => m SkolemScope
+ Language.PureScript.TypeChecker.Skolems: newSkolemScope :: MonadState CheckState m => m SkolemScope
- Language.PureScript.TypeChecker.Skolems: skolemEscapeCheck :: (MonadError MultipleErrors m) => Expr -> m ()
+ Language.PureScript.TypeChecker.Skolems: skolemEscapeCheck :: MonadError MultipleErrors m => Expr -> m ()
- Language.PureScript.TypeChecker.TypeSearch: typeSearch :: Maybe [(Ident, InstanceContext, Constraint)] -> Environment -> CheckState -> Type -> Map (Qualified Ident) Type
+ Language.PureScript.TypeChecker.TypeSearch: typeSearch :: Maybe [(Ident, InstanceContext, Constraint)] -> Environment -> CheckState -> Type -> ([(Qualified Text, Type)], Maybe [(Label, Type)])
- Language.PureScript.Types: ConstrainedType :: [Constraint] -> Type -> Type
+ Language.PureScript.Types: ConstrainedType :: Constraint -> Type -> Type
Files
- CONTRIBUTING.md +16/−2
- CONTRIBUTORS.md +108/−89
- LICENSE +1/−247
- README.md +1/−1
- app/Command/Bundle.hs +129/−0
- app/Command/Compile.hs +150/−0
- app/Command/Docs.hs +260/−0
- app/Command/Docs/Ctags.hs +13/−0
- app/Command/Docs/Etags.hs +13/−0
- app/Command/Docs/Html.hs +181/−0
- app/Command/Docs/Tags.hs +21/−0
- app/Command/Hierarchy.hs +111/−0
- app/Command/Ide.hs +213/−0
- app/Command/Publish.hs +52/−0
- app/Command/REPL.hs +379/−0
- app/Main.hs +64/−0
- app/Version.hs +23/−0
- app/static/index.html +10/−0
- app/static/index.js +63/−0
- app/static/normalize.css +427/−0
- app/static/pursuit.css +703/−0
- examples/docs/bower.json +1/−0
- examples/docs/resolutions.json +21/−0
- examples/docs/src/ConstrainedArgument.purs +2/−3
- examples/docs/src/TypeClassWithFunDeps.purs +1/−1
- examples/failing/1071.purs +1/−1
- examples/failing/1310.purs +1/−1
- examples/failing/2445.purs +0/−6
- examples/failing/2567.purs +5/−0
- examples/failing/2601.purs +1/−1
- examples/failing/2616.purs +9/−0
- examples/failing/DuplicateProperties.purs +12/−0
- examples/failing/DuplicateProperties1.purs +0/−12
- examples/failing/DuplicateProperties2.purs +0/−12
- examples/failing/InvalidDerivedInstance.purs +8/−0
- examples/failing/InvalidDerivedInstance2.purs +6/−0
- examples/failing/LetPatterns1.purs +10/−0
- examples/failing/LetPatterns2.purs +14/−0
- examples/failing/LetPatterns3.purs +13/−0
- examples/failing/LetPatterns4.purs +6/−0
- examples/failing/NonExhaustivePatGuard.purs +5/−0
- examples/failing/Superclasses5.purs +3/−3
- examples/failing/UnusableTypeClassMethod.purs +7/−0
- examples/failing/UnusableTypeClassMethodConflictingIdent.purs +7/−0
- examples/failing/UnusableTypeClassMethodSynonym.purs +9/−0
- examples/passing/1110.purs +26/−0
- examples/passing/1335.purs +14/−14
- examples/passing/1697.purs +3/−3
- examples/passing/1991.purs +1/−1
- examples/passing/2609.purs +12/−0
- examples/passing/2609/Eg.purs +6/−0
- examples/passing/2616.purs +13/−0
- examples/passing/2626.purs +13/−0
- examples/passing/2663.purs +9/−0
- examples/passing/2689.purs +36/−0
- examples/passing/2695.purs +13/−0
- examples/passing/2756.purs +20/−0
- examples/passing/CheckTypeClass.purs +2/−2
- examples/passing/ClassRefSyntax.purs +1/−1
- examples/passing/Collatz.purs +2/−2
- examples/passing/Console.purs +3/−3
- examples/passing/ConstraintParens.purs +12/−0
- examples/passing/DctorOperatorAlias.purs +1/−1
- examples/passing/Do.purs +2/−2
- examples/passing/DuplicateProperties.purs +27/−0
- examples/passing/Eff.purs +2/−2
- examples/passing/EntailsKindedType.purs +2/−2
- examples/passing/ExtendedInfixOperators.purs +1/−1
- examples/passing/Fib.purs +2/−2
- examples/passing/FinalTagless.purs +1/−1
- examples/passing/FunWithFunDeps.purs +4/−4
- examples/passing/GenericsRep.purs +8/−0
- examples/passing/Guards.purs +36/−2
- examples/passing/KindedType.purs +5/−5
- examples/passing/LetPattern.purs +196/−0
- examples/passing/MutRec2.purs +1/−1
- examples/passing/MutRec3.purs +1/−1
- examples/passing/NakedConstraint.purs +1/−1
- examples/passing/NewtypeClass.purs +2/−1
- examples/passing/Operators.purs +1/−1
- examples/passing/OverlappingInstances2.purs +27/−27
- examples/passing/OverlappingInstances3.purs +20/−20
- examples/passing/PrimedTypeName.purs +20/−20
- examples/passing/Rank2TypeSynonym.purs +1/−1
- examples/passing/RebindableSyntax.purs +43/−43
- examples/passing/RowPolyInstanceContext.purs +1/−1
- examples/passing/RowUnion.js +10/−0
- examples/passing/RowUnion.purs +68/−0
- examples/passing/Sequence.purs +1/−1
- examples/passing/SequenceDesugared.purs +9/−9
- examples/passing/StringEscapes.purs +26/−26
- examples/passing/Superclasses1.purs +1/−1
- examples/passing/Superclasses3.purs +3/−3
- examples/passing/TypeClasses.purs +4/−4
- examples/passing/TypeWildcards.purs +1/−1
- examples/passing/TypedBinders.purs +3/−3
- examples/passing/UnicodeType.purs +2/−2
- examples/passing/UnifyInTypeInstanceLookup.purs +2/−2
- examples/passing/UnknownInTypeClassLookup.purs +1/−1
- examples/passing/UsableTypeClassMethods.purs +35/−0
- examples/warning/ShadowedBinderPatternGuard.purs +7/−0
- examples/warning/ShadowedNameParens.purs +5/−0
- hierarchy/Main.hs +0/−119
- psc-bundle/Main.hs +0/−147
- psc-docs/Ctags.hs +0/−13
- psc-docs/Etags.hs +0/−13
- psc-docs/Main.hs +0/−253
- psc-docs/Tags.hs +0/−21
- psc-ide-client/Main.hs +0/−50
- psc-ide-server/Main.hs +0/−187
- psc-package/Main.hs +0/−423
- psc-publish/Main.hs +0/−57
- psc/Main.hs +0/−182
- psci/Main.hs +0/−377
- psci/static/index.html +0/−10
- psci/static/index.js +0/−63
- purescript.cabal +62/−176
- src/Language/PureScript/AST/Binders.hs +9/−1
- src/Language/PureScript/AST/Declarations.hs +48/−8
- src/Language/PureScript/AST/Exported.hs +1/−1
- src/Language/PureScript/AST/Traversals.hs +80/−41
- src/Language/PureScript/Bundle.hs +10/−9
- src/Language/PureScript/CodeGen.hs +1/−1
- src/Language/PureScript/CodeGen/JS.hs +155/−166
- src/Language/PureScript/CodeGen/JS/AST.hs +0/−398
- src/Language/PureScript/CodeGen/JS/Common.hs +6/−18
- src/Language/PureScript/CodeGen/JS/Optimizer.hs +0/−73
- src/Language/PureScript/CodeGen/JS/Optimizer/Blocks.hs +0/−32
- src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs +0/−78
- src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs +0/−385
- src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs +0/−137
- src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs +0/−120
- src/Language/PureScript/CodeGen/JS/Optimizer/Unused.hs +0/−35
- src/Language/PureScript/CodeGen/JS/Printer.hs +272/−0
- src/Language/PureScript/Constants.hs +15/−6
- src/Language/PureScript/CoreFn/Desugar.hs +49/−63
- src/Language/PureScript/CoreFn/Meta.hs +2/−2
- src/Language/PureScript/CoreImp.hs +13/−0
- src/Language/PureScript/CoreImp/AST.hs +224/−0
- src/Language/PureScript/CoreImp/Optimizer.hs +60/−0
- src/Language/PureScript/CoreImp/Optimizer/Blocks.hs +28/−0
- src/Language/PureScript/CoreImp/Optimizer/Common.hs +76/−0
- src/Language/PureScript/CoreImp/Optimizer/Inliner.hs +383/−0
- src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs +134/−0
- src/Language/PureScript/CoreImp/Optimizer/TCO.hs +123/−0
- src/Language/PureScript/CoreImp/Optimizer/Unused.hs +34/−0
- src/Language/PureScript/Docs/AsHtml.hs +7/−4
- src/Language/PureScript/Docs/Convert/ReExports.hs +1/−1
- src/Language/PureScript/Docs/Convert/Single.hs +1/−1
- src/Language/PureScript/Docs/Prim.hs +9/−6
- src/Language/PureScript/Docs/RenderedCode/RenderType.hs +5/−9
- src/Language/PureScript/Docs/Types.hs +5/−3
- src/Language/PureScript/Environment.hs +102/−136
- src/Language/PureScript/Errors.hs +75/−28
- src/Language/PureScript/Externs.hs +12/−10
- src/Language/PureScript/Ide.hs +1/−1
- src/Language/PureScript/Ide/Error.hs +38/−6
- src/Language/PureScript/Ide/Externs.hs +5/−5
- src/Language/PureScript/Ide/Imports.hs +72/−79
- src/Language/PureScript/Ide/Pursuit.hs +1/−5
- src/Language/PureScript/Ide/Rebuild.hs +9/−9
- src/Language/PureScript/Ide/Reexports.hs +8/−5
- src/Language/PureScript/Ide/SourceFile.hs +4/−28
- src/Language/PureScript/Ide/Types.hs +29/−37
- src/Language/PureScript/Ide/Util.hs +8/−17
- src/Language/PureScript/Interactive.hs +18/−8
- src/Language/PureScript/Interactive/Completion.hs +6/−4
- src/Language/PureScript/Interactive/Directive.hs +6/−3
- src/Language/PureScript/Interactive/Message.hs +14/−11
- src/Language/PureScript/Interactive/Module.hs +12/−11
- src/Language/PureScript/Interactive/Parser.hs +23/−21
- src/Language/PureScript/Interactive/Types.hs +7/−3
- src/Language/PureScript/Kinds.hs +0/−3
- src/Language/PureScript/Linter.hs +5/−4
- src/Language/PureScript/Linter/Exhaustive.hs +30/−22
- src/Language/PureScript/Linter/Imports.hs +7/−6
- src/Language/PureScript/Make.hs +6/−5
- src/Language/PureScript/ModuleDependencies.hs +16/−16
- src/Language/PureScript/Names.hs +1/−1
- src/Language/PureScript/Options.hs +9/−31
- src/Language/PureScript/Parser.hs +23/−23
- src/Language/PureScript/Parser/Declarations.hs +104/−74
- src/Language/PureScript/Parser/Kinds.hs +11/−9
- src/Language/PureScript/Parser/Lexer.hs +9/−0
- src/Language/PureScript/Parser/Types.hs +26/−5
- src/Language/PureScript/Pretty.hs +4/−9
- src/Language/PureScript/Pretty/JS.hs +0/−303
- src/Language/PureScript/Pretty/Types.hs +4/−5
- src/Language/PureScript/Pretty/Values.hs +9/−9
- src/Language/PureScript/Publish.hs +88/−107
- src/Language/PureScript/Publish/ErrorsWarnings.hs +57/−53
- src/Language/PureScript/Publish/Utils.hs +8/−35
- src/Language/PureScript/Sugar.hs +4/−1
- src/Language/PureScript/Sugar/BindingGroups.hs +15/−13
- src/Language/PureScript/Sugar/CaseDeclarations.hs +248/−29
- src/Language/PureScript/Sugar/DoNotation.hs +27/−25
- src/Language/PureScript/Sugar/LetPattern.hs +47/−0
- src/Language/PureScript/Sugar/Names.hs +20/−16
- src/Language/PureScript/Sugar/Names/Common.hs +3/−2
- src/Language/PureScript/Sugar/ObjectWildcards.hs +8/−8
- src/Language/PureScript/Sugar/TypeClasses.hs +35/−36
- src/Language/PureScript/Sugar/TypeClasses/Deriving.hs +148/−105
- src/Language/PureScript/Sugar/TypeDeclarations.hs +3/−5
- src/Language/PureScript/TypeChecker.hs +37/−13
- src/Language/PureScript/TypeChecker/Entailment.hs +68/−44
- src/Language/PureScript/TypeChecker/Kinds.hs +5/−6
- src/Language/PureScript/TypeChecker/Monad.hs +5/−0
- src/Language/PureScript/TypeChecker/Rows.hs +0/−53
- src/Language/PureScript/TypeChecker/Skolems.hs +78/−76
- src/Language/PureScript/TypeChecker/Subsumption.hs +9/−26
- src/Language/PureScript/TypeChecker/TypeSearch.hs +36/−3
- src/Language/PureScript/TypeChecker/Types.hs +98/−70
- src/Language/PureScript/TypeChecker/Unify.hs +46/−31
- src/Language/PureScript/TypeClassDictionaries.hs +7/−0
- src/Language/PureScript/Types.hs +50/−88
- stack.yaml +0/−1
- tests/Language/PureScript/Ide/ImportsSpec.hs +39/−0
- tests/Language/PureScript/Ide/ReexportsSpec.hs +16/−13
- tests/Language/PureScript/Ide/SourceFileSpec.hs +1/−1
- tests/Language/PureScript/Ide/StateSpec.hs +2/−0
- tests/Language/PureScript/Ide/Test.hs +4/−4
- tests/TestDocs.hs +6/−8
- tests/TestPscPublish.hs +6/−4
- tests/TestPsci.hs +5/−121
- tests/TestPsci/CommandTest.hs +35/−0
- tests/TestPsci/CompletionTest.hs +108/−0
- tests/TestPsci/TestEnv.hs +81/−0
- tests/TestUtils.hs +2/−0
- tests/support/bower.json +16/−13
- tests/support/prelude-resolutions.json +7/−0
CONTRIBUTING.md view
@@ -10,10 +10,24 @@ Please follow the following guidelines: -- Add at least a test to `examples/passing/` and possibly to `examples/failing`.+- Add at least a test to `examples/passing/` and possibly to `examples/failing/`. - Build the binaries and libs with `stack build`-- Run the test suite with `stack test`. You will need `npm`, `bower` and `node` on your PATH to run the tests.+- Make sure that all test suites are passing. Run the test suites with `stack test`. - Build the core libraries by running the script in `core-tests`.++## Tests++Run all test suites with `stack test`. You will need `npm`, `bower` and `node` on your PATH to run the tests.++To build and run a specific test in `examples/passing/` or `examples/failing/`, execute the following commands.++``` bash+# Build+stack exec psc -- 'tests/support/bower_components/purescript-*/src/**/*.purs' examples/blah/Blah.purs++# Run+node -e "require('./output/Main/').main()"+``` ## Code Review
CONTRIBUTORS.md view
@@ -2,96 +2,115 @@ This file lists the contributors to the PureScript compiler project, and the terms under which their code is licensed. -### Individuals+### Contributors using Standard Terms -- [@5outh](https://github.com/5outh) (Benjamin Kovach) - My existing contributions and all future contributions until further notice are Copyright Benjamin Kovach, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@andreypopp](https://github.com/andreypopp) (Andrey Popp) My existing contributions and all future contributions until further notice are Copyright Andrey Popp, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@andyarvanitis](https://github.com/andyarvanitis) (Andy Arvanitis) My existing contributions and all future contributions until further notice are Copyright Andy Arvanitis, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@anthok88](https://github.com/anthoq88) - My existing contributions and all future contributions until further notice are Copyright anthoq88, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license-- [@ardumont](https://github.com/ardumont) (Antoine R. Dumont) My existing contributions and all future contributions until further notice are Copyright Antoine R. Dumont, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@aspidites](https://github.com/aspidites) (Edwin Marshall) My existing contributions and all future contributions until further notice are Copyright Edwin Marshall, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@bagl](https://github.com/bagl) (Petr Vapenka) My existing contributions and all future contributions until further notice are Copyright Petr Vapenka, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@balajirrao](https://github.com/balajirrao) (Balaji Rao) - My existing contributions and all future contributions until further notice are Copyright Balaji Rao, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@bergmark](https://github.com/bergmark) (Adam Bergmark) - My existing contributions and all future contributions until further notice are Copyright Adam Bergmark, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@bmjames](https://github.com/bmjames) (Ben James) My existing contributions and all future contributions until further notice are Copyright Ben James, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@Bogdanp](https://github.com/Bogdanp) (Bogdan Paul Popa) My existing contributions and all future contributions until further notice are Copyright Bogdan Paul Popa, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@bsermons](https://github.com/bsermons) (Brian Sermons) My existing contributions and all future contributions until further notice are Copyright Brian Sermons, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@cdepillabout](https://github.com/cdepillabout) (Dennis Gosnell) My existing contributions and all future contributions until further notice are Copyright Dennis Gosnell, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@charleso](https://github.com/charleso) (Charles O'Farrell) My existing contributions to the PureScript compiler and all future contributions to the PureScript compiler until further notice, are Copyright Charles O'Farrell, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@chrisdone](https://github.com/chrisdone) (Chris Done) - My existing contributions and all future contributions until further notice are Copyright Chris Done, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@chrissmoak](https://github.com/chrissmoak) (Chris Smoak) My existing contributions to the PureScript compiler and all future contributions to the PureScript compiler until further notice, are Copyright Chris Smoak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@codedmart](https://github.com/codedmart) (Brandon Martin) My existing contributions and all future contributions until further notice are Copyright Brandon Martin, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@davidchambers](https://github.com/davidchambers) (David Chambers) My existing contributions and all future contributions until further notice are Copyright David Chambers, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@DavidLindbom](https://github.com/DavidLindbom) (David Lindbom) My existing contributions and all future contributions until further notice are Copyright David Lindbom, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@dckc](https://github.com/dckc) (Dan Connolly) My existing contributions and all future contributions until further notice are Copyright Dan Connolly, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@dylex](https://github.com/dylex) (Dylan Simon) My existing and all future contributions to the PureScript compiler until further notice are Copyright Dylan Simon, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@eamelink](https://github.com/eamelink) (Erik Bakker) - My existing contributions and all future contributions until further notice are Copyright Erik Bakker, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@epost](https://github.com/epost) (Erik Post) - My existing contributions and all future contributions until further notice are Copyright Erik Post, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license-- [@erdeszt](https://github.com/erdeszt) (Tibor Erdesz) My existing contributions and all future contributions until further notice are Copyright Tibor Erdesz, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@etrepum](https://github.com/etrepum) (Bob Ippolito) My existing contributions and all future contributions until further notice are Copyright Bob Ippolito, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@faineance](https://github.com/faineance) My existing contributions and all future contributions until further notice are Copyright faineance, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@felixSchl](https://github.com/felixSchl) (Felix Schlitter) My existing contributions and all future contributions until further notice are Copyright Felix Schlitter, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@FrigoEU](https://github.com/FrigoEU) (Simon Van Casteren) My existing contributions and all future contributions until further notice are Copyright Simon Van Casteren, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@garyb](https://github.com/garyb) (Gary Burgess) My existing contributions and all future contributions until further notice are Copyright Gary Burgess, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@hdgarrood](https://github.com/hdgarrood) (Harry Garrood) My existing contributions and all future contributions until further notice are Copyright Harry Garrood, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@ianbollinger](https://github.com/ianbollinger) (Ian D. Bollinger) My existing contributions and all future contributions until further notice are Copyright Ian D. Bollinger, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@ilovezfs](https://github.com/ilovezfs) - My existing contributions and all future contributions until further notice are Copyright ilovezfs, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license-- [@izgzhen](https://github.com/izgzhen) (Zhen Zhang) My existing contributions and all future contributions until further notice are Copyright Zhen Zhang, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@jacereda](https://github.com/jacereda) (Jorge Acereda) My existing contributions and all future contributions until further notice are Copyright Jorge Acereda, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@japesinator](https://github.com/japesinator) (JP Smith) My existing contributions and all future contributions until further notice are Copyright JP Smith, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@joneshf](https://github.com/joneshf) (Hardy Jones) - My existing contributions and all future contributions until further notice are Copyright Hardy Jones, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@kika](https://github.com/kika) (Kirill Pertsev) - My existing contributions and all future contributions until further notice are Copyright Kirill Pertsev, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@kRITZCREEK](https://github.com/kRITZCREEK) (Christoph Hegemann) - My existing contributions and all future contributions until further notice are Copyright Christoph Hegemann, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@L8D](https://github.com/L8D) (Tenor Biel) My existing contributions and all future contributions until further notice are Copyright Tenor Biel, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@leighman](http://github.com/leighman) (Jack Leigh) My existing contributions and all future contributions until further notice are Copyright Jack Leigh, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@LiamGoodacre](https://github.com/LiamGoodacre) (Liam Goodacre) My existing contributions and all future contributions until further notice are Copyright Liam Goodacre, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@lukerandall](https://github.com/lukerandall) (Luke Randall) My existing contributions and all future contributions until further notice are Copyright Luke Randall, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@mgmeier](https://github.com/mgmeier) (Michael Karg) My existing contributions and all future contributions until further notice are Copyright Michael Gilliland, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@michaelficarra](https://github.com/michaelficarra) (Michael Ficarra) My existing contributions and all future contributions until further notice are Copyright Michael Ficarra, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@MichaelXavier](https://github.com/MichaelXavier) (Michael Xavier) - My existing contributions and all future contributions until further notice are Copyright Michael Xavier, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@mjgpy3](https://github.com/mjgpy3) (Michael Gilliland) My existing contributions and all future contributions until further notice are Copyright Michael Gilliland, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@mpietrzak](https://github.com/mpietrzak) (Maciej Pietrzak) My existing contributions and all future contributions until further notice are Copyright Maciej Pietrzak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@mrhania](https://github.com/mrhania) (Łukasz Hanuszczak) - My existing contributions and all future contributions until further notice are Copyright Łukasz Hanuszczak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@nagisa](https://github.com/nagisa) I hereby release my [only contribution](https://github.com/purescript/purescript/commit/80287a5d0de619862d3b4cda9c1ee276d18fdcd8) into public domain.-- [@natefaubion](https://github.com/natefaubion) (Nathan Faubion) My existing contributions and all future contributions until further notice are Copyright Nathan Faubion, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@nicodelpiano](https://github.com/nicodelpiano) (Nicolas Del Piano) My existing contributions and all future contributions until further notice are Copyright Nicolas Del Piano, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@nullobject](https://github.com/nullobject) (Josh Bassett) My existing contributions and all future contributions until further notice are Copyright Josh Bassett, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@nwolverson](https://github.com/nwolverson) (Nicholas Wolverson) My existing contributions and all future contributions until further notice are Copyright Nicholas Wolverson, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@osa1](https://github.com/osa1) (Ömer Sinan Ağacan) - My existing contributions and all future contributions until further notice are Copyright Ömer Sinan Ağacan, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@paf31](https://github.com/paf31) (Phil Freeman) My existing contributions and all future contributions until further notice are Copyright Phil Freeman, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@passy](https://github.com/passy) (Pascal Hartig) My existing contributions and all future contributions until further notice are Copyright Pascal Hartig, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@paulyoung](https://github.com/paulyoung) (Paul Young) My existing contributions and all future contributions until further notice are Copyright Paul Young, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@pelotom](https://github.com/pelotom) (Thomas Crockett) My existing contributions and all future contributions until further notice are Copyright Thomas Crockett, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@phadej](https://github.com/phadej) (Oleg Grenrus) My existing contributions and all future contributions until further notice are Copyright Oleg Grenrus, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@phiggins](https://github.com/phiggins) (Pete Higgins) My existing contributions and all future contributions until further notice are Copyright Pete Higgins, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@philopon](https://github.com/philopon) (Hirotomo Moriwaki) - My existing contributions and all future contributions until further notice are Copyright Hirotomo Moriwaki, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@pseudonom](https://github.com/pseudonom) (Eric Easley) My existing contributions and all future contributions until further notice are Copyright Eric Easley, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@puffnfresh](https://github.com/puffnfresh) (Brian McKenna) All contributions I made during June 2015 were during employment at [SlamData, Inc.](#companies) who owns the copyright. I assign copyright of all my personal contributions before June 2015 to the owners of the PureScript compiler.-- [@rightfold](https://github.com/rightfold) (rightfold) My existing contributions and all future contributions until further notice are Copyright rightfold, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](https://opensource.org/licenses/MIT).-- [@robdaemon](https://github.com/robdaemon) (Robert Roland) My existing contributions and all future contributions until further notice are Copyright Robert Roland, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@RossMeikleham](https://github.com/RossMeikleham) (Ross Meikleham) My existing contributions and all future contributions until further notice are Copyright Ross Meikleham, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@rvion](https://github.com/rvion) (Rémi Vion) My existing contributions and all future contributions until further notice are Copyright Rémi Vion, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@sebastiaanvisser](https://github.com/sebastiaanvisser) (Sebastiaan Visser) - My existing contributions and all future contributions until further notice are Copyright Sebastiaan Visser, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@senju](https://github.com/senju) - My existing contributions and all future contributions until further notice are Copyright senju, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@sharkdp](https://github.com/sharkdp) (David Peter) My existing contributions and all future contributions until further notice are Copyright David Peter, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@soupi](https://github.com/soupi) (Gil Mizrahi) My existing contributions and all future contributions until further notice are Copyright Gil Mizrahi, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@sztupi](https://github.com/sztupi) (Attila Sztupak) My existing contributions and all future contributions until further notice are Copyright Attila Sztupak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@taktoa](https://github.com/taktoa) (Remy Goldschmidt) My existing contributions and all future contributions until further notice are Copyright Remy Goldschmidt, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@taku0](https://github.com/taku0) - My existing contributions and all future contributions until further notice are Copyright taku0, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@tfausak](https://github.com/tfausak) (Taylor Fausak) My existing contributions and all future contributions until further notice are Copyright Taylor Fausak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@tmcgilchrist](https://github.com/tmcgilchrist) (Tim McGilchrist) My existing contributions and all future contributions until further notice are Copyright Tim McGilchrist, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@trofi](https://github.com/trofi) (Sergei Trofimovich) My existing contributions and all future contributions until further notice are Copyright Sergei Trofimovich, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@utkarshkukreti](https://github.com/utkarshkukreti) (Utkarsh Kukreti) My existing contributions and all future contributions until further notice are Copyright Utkarsh Kukreti, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@vkorablin](https://github.com/vkorablin) (Vladimir Korablin) - My existing contributions and all future contributions until further notice are Copyright Vladimir Korablin, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.-- [@zudov](https://github.com/zudov) (Konstantin Zudov) My existing contributions and all future contributions until further notice are Copyright Konstantin Zudov, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@brandonhamilton](https://github.com/brandonhamilton) (Brandon Hamilton) My existing contributions and all future contributions until further notice are Copyright Brandon Hamilton, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@bbqbaron](https://github.com/bbqbaron) (Eric Loren) My existing contributions and all future contributions until further notice are Copyright Eric Loren, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@RyanGlScott](https://github.com/RyanGlScott) (Ryan Scott) My existing contributions and all future contributions until further notice are Copyright Ryan Scott, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@seungha-kim](https://github.com/seungha-kim) (Seungha Kim) My existing contributions and all future contributions until further notice are Copyright Seungha Kim, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@matthewleon](https://github.com/matthewleon) (Matthew Leon) My existing contributions and all future contributions until further notice are Copyright Matthew Leon, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@alexbiehl](https://github.com/alexbiehl) (Alexander Biehl) My existing contributions and all future contributions until further notice are Copyright Alexander Biehl, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).-- [@noraesae](https://github.com/noraesae) (Hyunje Jun) My existing contributions and all future contributions until further notice are Copyright Hyunje Jun, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).+Contributors listed here agree to license their contributions under the following terms: +> My existing contributions and all future contributions until further notice are Copyright {Name}, and are licensed to the owners and users of the PureScript compiler project under the terms of the {License}.++By adding your name to the list below, you agree to license your contributions under these following terms.++If you would prefer to use different terms, please use the section below instead.++| Username | Name | License |+| :------- | :--- | :------ |+| [@5outh](https://github.com/5outh) | Benjamin Kovach | MIT license |+| [@alexbiehl](https://github.com/alexbiehl) | Alexander Biehl | [MIT license](http://opensource.org/licenses/MIT) |+| [@andreypopp](https://github.com/andreypopp) | Andrey Popp | MIT license |+| [@andyarvanitis](https://github.com/andyarvanitis) | Andy Arvanitis | [MIT license](http://opensource.org/licenses/MIT) |+| [@anthok88](https://github.com/anthok88) | anthoq88 | MIT license |+| [@ardumont](https://github.com/ardumont) | Antoine R. Dumont | [MIT license](http://opensource.org/licenses/MIT) |+| [@aspidites](https://github.com/aspidites) | Edwin Marshall | [MIT license](http://opensource.org/licenses/MIT) |+| [@bagl](https://github.com/bagl) | Petr Vapenka | [MIT license](http://opensource.org/licenses/MIT) |+| [@balajirrao](https://github.com/balajirrao) | Balaji Rao | MIT license |+| [@bbqbaron](https://github.com/bbqbaron) | Eric Loren | [MIT license](http://opensource.org/licenses/MIT) |+| [@bergmark](https://github.com/bergmark) | Adam Bergmark | MIT license |+| [@bmjames](https://github.com/bmjames) | Ben James | [MIT license](http://opensource.org/licenses/MIT) |+| [@Bogdanp](https://github.com/Bogdanp) | Bogdan Paul Popa | [MIT license](http://opensource.org/licenses/MIT) |+| [@brandonhamilton](https://github.com/brandonhamilton) | Brandon Hamilton | [MIT license](http://opensource.org/licenses/MIT) |+| [@bsermons](https://github.com/bsermons) | Brian Sermons | [MIT license](http://opensource.org/licenses/MIT) |+| [@cdepillabout](https://github.com/cdepillabout) | Dennis Gosnell | [MIT license](http://opensource.org/licenses/MIT) |+| [@chrisdone](https://github.com/chrisdone) | Chris Done | MIT license |+| [@codedmart](https://github.com/codedmart) | Brandon Martin | [MIT license](http://opensource.org/licenses/MIT) |+| [@davidchambers](https://github.com/davidchambers) | David Chambers | [MIT license](http://opensource.org/licenses/MIT) |+| [@DavidLindbom](https://github.com/DavidLindbom) | David Lindbom | [MIT license](http://opensource.org/licenses/MIT) |+| [@dckc](https://github.com/dckc) | Dan Connolly | [MIT license](http://opensource.org/licenses/MIT) |+| [@eamelink](https://github.com/eamelink) | Erik Bakker | MIT license |+| [@epost](https://github.com/epost) | Erik Post | MIT license |+| [@erdeszt](https://github.com/erdeszt) | Tibor Erdesz | [MIT license](http://opensource.org/licenses/MIT) |+| [@etrepum](https://github.com/etrepum) | Bob Ippolito | [MIT license](http://opensource.org/licenses/MIT) |+| [@faineance](https://github.com/faineance) | faineance | [MIT license](http://opensource.org/licenses/MIT) |+| [@felixSchl](https://github.com/felixSchl) | Felix Schlitter | [MIT license](http://opensource.org/licenses/MIT) |+| [@FrigoEU](https://github.com/FrigoEU) | Simon Van Casteren | [MIT license](http://opensource.org/licenses/MIT) |+| [@garyb](https://github.com/garyb) | Gary Burgess | [MIT license](http://opensource.org/licenses/MIT) |+| [@hdgarrood](https://github.com/hdgarrood) | Harry Garrood | [MIT license](http://opensource.org/licenses/MIT) |+| [@ianbollinger](https://github.com/ianbollinger) | Ian D. Bollinger | [MIT license](http://opensource.org/licenses/MIT) |+| [@ilovezfs](https://github.com/ilovezfs) | ilovezfs | MIT license |+| [@izgzhen](https://github.com/izgzhen) | Zhen Zhang | [MIT license](http://opensource.org/licenses/MIT) |+| [@jacereda](https://github.com/jacereda) | Jorge Acereda | [MIT license](http://opensource.org/licenses/MIT) |+| [@japesinator](https://github.com/japesinator) | JP Smith | [MIT license](http://opensource.org/licenses/MIT) |+| [@joneshf](https://github.com/joneshf) | Hardy Jones | MIT license |+| [@kika](https://github.com/kika) | Kirill Pertsev | MIT license |+| [@kRITZCREEK](https://github.com/kRITZCREEK) | Christoph Hegemann | MIT license |+| [@L8D](https://github.com/L8D) | Tenor Biel | [MIT license](http://opensource.org/licenses/MIT) |+| [@LiamGoodacre](https://github.com/LiamGoodacre) | Liam Goodacre | [MIT license](http://opensource.org/licenses/MIT) |+| [@lukerandall](https://github.com/lukerandall) | Luke Randall | [MIT license](http://opensource.org/licenses/MIT) |+| [@matthewleon](https://github.com/matthewleon) | Matthew Leon | [MIT license](http://opensource.org/licenses/MIT) |+| [@mcoffin](https://github.com/mcoffin) | Matt Coffin | [MIT license](http://opensource.org/licenses/MIT) |+| [@mrkgnao](https://github.com/mrkgnao) | Soham Chowdhury | [MIT license](http://opensource.org/licenses/MIT) |+| [@mgmeier](https://github.com/mgmeier) | Michael Gilliland | [MIT license](http://opensource.org/licenses/MIT) |+| [@michaelficarra](https://github.com/michaelficarra) | Michael Ficarra | [MIT license](http://opensource.org/licenses/MIT) |+| [@MichaelXavier](https://github.com/MichaelXavier) | Michael Xavier | MIT license |+| [@mjgpy3](https://github.com/mjgpy3) | Michael Gilliland | [MIT license](http://opensource.org/licenses/MIT) |+| [@mpietrzak](https://github.com/mpietrzak) | Maciej Pietrzak | [MIT license](http://opensource.org/licenses/MIT) |+| [@mrhania](https://github.com/mrhania) | Łukasz Hanuszczak | [MIT license](http://opensource.org/licenses/MIT) |+| [@natefaubion](https://github.com/natefaubion) | Nathan Faubion | [MIT license](http://opensource.org/licenses/MIT) |+| [@nicodelpiano](https://github.com/nicodelpiano) | Nicolas Del Piano | [MIT license](http://opensource.org/licenses/MIT) |+| [@noraesae](https://github.com/noraesae) | Hyunje Jun | [MIT license](http://opensource.org/licenses/MIT) |+| [@nullobject](https://github.com/nullobject) | Josh Bassett | [MIT license](http://opensource.org/licenses/MIT) |+| [@nwolverson](https://github.com/nwolverson) | Nicholas Wolverson | [MIT license](http://opensource.org/licenses/MIT) |+| [@osa1](https://github.com/osa1) | Ömer Sinan Ağacan | MIT license |+| [@paf31](https://github.com/paf31) | Phil Freeman | [MIT license](http://opensource.org/licenses/MIT) |+| [@passy](https://github.com/passy) | Pascal Hartig | [MIT license](http://opensource.org/licenses/MIT) |+| [@paulyoung](https://github.com/paulyoung) | Paul Young | [MIT license](http://opensource.org/licenses/MIT) |+| [@pelotom](https://github.com/pelotom) | Thomas Crockett | [MIT license](http://opensource.org/licenses/MIT) |+| [@phadej](https://github.com/phadej) | Oleg Grenrus | [MIT license](http://opensource.org/licenses/MIT) |+| [@phiggins](https://github.com/phiggins) | Pete Higgins | [MIT license](http://opensource.org/licenses/MIT) |+| [@philopon](https://github.com/philopon) | Hirotomo Moriwaki | [MIT license](http://opensource.org/licenses/MIT) |+| [@pseudonom](https://github.com/pseudonom) | Eric Easley | [MIT license](http://opensource.org/licenses/MIT) |+| [@rightfold](https://github.com/rightfold) | rightfold | [MIT license](https://opensource.org/licenses/MIT) |+| [@robdaemon](https://github.com/robdaemon) | Robert Roland | [MIT license](http://opensource.org/licenses/MIT) |+| [@RossMeikleham](https://github.com/RossMeikleham) | Ross Meikleham | [MIT license](http://opensource.org/licenses/MIT) |+| [@rvion](https://github.com/rvion) | Rémi Vion | [MIT license](http://opensource.org/licenses/MIT) |+| [@RyanGlScott](https://github.com/RyanGlScott) | Ryan Scott | [MIT license](http://opensource.org/licenses/MIT) |+| [@sebastiaanvisser](https://github.com/sebastiaanvisser) | Sebastiaan Visser | MIT license |+| [@senju](https://github.com/senju) | senju | [MIT license](http://opensource.org/licenses/MIT) |+| [@seungha-kim](https://github.com/seungha-kim) | Seungha Kim | [MIT license](http://opensource.org/licenses/MIT) |+| [@sharkdp](https://github.com/sharkdp) | David Peter | [MIT license](http://opensource.org/licenses/MIT) |+| [@soupi](https://github.com/soupi) | Gil Mizrahi | [MIT license](http://opensource.org/licenses/MIT) |+| [@sztupi](https://github.com/sztupi) | Attila Sztupak | [MIT license](http://opensource.org/licenses/MIT) |+| [@taktoa](https://github.com/taktoa) | Remy Goldschmidt | [MIT license](http://opensource.org/licenses/MIT) |+| [@taku0](https://github.com/taku0) | taku0 | [MIT license](http://opensource.org/licenses/MIT) |+| [@tfausak](https://github.com/tfausak) | Taylor Fausak | [MIT license](http://opensource.org/licenses/MIT) |+| [@tmcgilchrist](https://github.com/tmcgilchrist) | Tim McGilchrist | [MIT license](http://opensource.org/licenses/MIT) |+| [@trofi](https://github.com/trofi) | Sergei Trofimovich | [MIT license](http://opensource.org/licenses/MIT) |+| [@utkarshkukreti](https://github.com/utkarshkukreti) | Utkarsh Kukreti | [MIT license](http://opensource.org/licenses/MIT) |+| [@vkorablin](https://github.com/vkorablin) | Vladimir Korablin | MIT license |+| [@zudov](https://github.com/zudov) | Konstantin Zudov | [MIT license](http://opensource.org/licenses/MIT) |++### Contributors using Modified Terms++| Username | Name | Terms |+| :------- | :--- | :------ |+| [@charleso](https://github.com/charleso) | Charles O'Farrell | My existing contributions to the PureScript compiler and all future contributions to the PureScript compiler until further notice, are Copyright Charles O'Farrell, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). |+| [@chrissmoak](https://github.com/chrissmoak) | Chris Smoak | My existing contributions to the PureScript compiler and all future contributions to the PureScript compiler until further notice, are Copyright Chris Smoak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). |+| [@dylex](https://github.com/dylex) | Dylan Simon | My existing and all future contributions to the PureScript compiler until further notice are Copyright Dylan Simon, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). |+| [@leighman](http://github.com/leighman) | Jack Leigh | My existing contributions and all future contributions until further notice are Copyright Jack Leigh, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). |+| [@nagisa](https://github.com/nagisa) | nagisa | I hereby release my [only contribution](https://github.com/purescript/purescript/commit/80287a5d0de619862d3b4cda9c1ee276d18fdcd8) into public domain. |+| [@puffnfresh](https://github.com/puffnfresh) | Brian McKenna | All contributions I made during June 2015 were during employment at [SlamData, Inc.](#companies) who owns the copyright. I assign copyright of all my personal contributions before June 2015 to the owners of the PureScript compiler. |+ ### Companies -- [@slamdata](https://github.com/slamdata) (SlamData, Inc.) Speaking on behalf of SlamData for SlamData employees, our existing contributions and all future contributions to the PureScript compiler are, until further notice, Copyright SlamData Inc., and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). - @jdegoes+| Username | Company | Terms |+| :------- | :--- | :------ |+| [@slamdata](https://github.com/slamdata) | SlamData, Inc. | Speaking on behalf of SlamData for SlamData employees, our existing contributions and all future contributions to the PureScript compiler are, until further notice, Copyright SlamData Inc., and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT). - @jdegoes |
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013-16 Phil Freeman, (c) 2014-2016 Gary Burgess, and other+Copyright (c) 2013-17 Phil Freeman, (c) 2014-2017 Gary Burgess, and other contributors All rights reserved. @@ -79,7 +79,6 @@ fast-logger file-embed filepath- foldl free fsnotify ghc-prim@@ -87,7 +86,6 @@ haskeline hex hinotify- hostname hourglass http-client http-client-tls@@ -100,7 +98,6 @@ language-javascript lens lifted-base- managed memory mime-types mmorph@@ -108,12 +105,10 @@ monad-logger monad-loops mtl- mwc-random network network-uri old-locale old-time- optional-args optparse-applicative parallel parsec@@ -146,12 +141,9 @@ streaming-commons stringsearch syb- system-fileio- system-filepath tagged tagsoup template-haskell- temporary terminfo text time@@ -159,7 +151,6 @@ transformers transformers-base transformers-compat- turtle uniplate unix unix-compat@@ -2285,33 +2276,6 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -foldl LICENSE file:-- Copyright (c) 2013 Gabriel Gonzalez- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification,- are permitted provided that the following conditions are met:- * Redistributions of source code must retain the above copyright notice,- this list of conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice,- this list of conditions and the following disclaimer in the documentation- and/or other materials provided with the distribution.- * Neither the name of Gabriel Gonzalez nor the names of other contributors- may be used to endorse or promote products derived from this software- without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- free LICENSE file: Copyright 2008-2013 Edward Kmett@@ -2567,31 +2531,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -hostname LICENSE file:-- Copyright (c) 2008, Maximilian Bolingbroke- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification, are permitted- provided that the following conditions are met:-- * Redistributions of source code must retain the above copyright notice, this list of- conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice, this list of- conditions and the following disclaimer in the documentation and/or other materials- provided with the distribution.- * Neither the name of Maximilian Bolingbroke nor the names of other contributors may be used to- endorse or promote products derived from this software without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- hourglass LICENSE file: Copyright (c) 2014 Vincent Hanquez <vincent@snarc.org>@@ -2962,33 +2901,6 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -managed LICENSE file:-- Copyright (c) 2014 Gabriel Gonzalez- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification,- are permitted provided that the following conditions are met:- * Redistributions of source code must retain the above copyright notice,- this list of conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice,- this list of conditions and the following disclaimer in the documentation- and/or other materials provided with the distribution.- * Neither the name of Gabriel Gonzalez nor the names of other contributors- may be used to endorse or promote products derived from this software- without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- memory LICENSE file: Copyright (c) 2015 Vincent Hanquez <vincent@snarc.org>@@ -3160,35 +3072,6 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -mwc-random LICENSE file:-- Copyright (c) 2009, Bryan O'Sullivan- All rights reserved.-- Redistribution and use in source and binary forms, with or without- modification, are permitted provided that the following conditions- are met:-- * Redistributions of source code must retain the above copyright- notice, this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above- copyright notice, this list of conditions and the following- disclaimer in the documentation and/or other materials provided- with the distribution.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- network LICENSE file: Copyright (c) 2002-2010, The University Court of the University of Glasgow.@@ -3385,33 +3268,6 @@ ----------------------------------------------------------------------------- -optional-args LICENSE file:-- Copyright (c) 2015 Gabriel Gonzalez- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification,- are permitted provided that the following conditions are met:- * Redistributions of source code must retain the above copyright notice,- this list of conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice,- this list of conditions and the following disclaimer in the documentation- and/or other materials provided with the distribution.- * Neither the name of Gabriel Gonzalez nor the names of other contributors- may be used to endorse or promote products derived from this software- without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- optparse-applicative LICENSE file: Copyright (c) 2012, Paolo Capriotti@@ -4499,56 +4355,6 @@ ----------------------------------------------------------------------------- -system-fileio LICENSE file:-- Copyright (c) 2011 John Millikin-- Permission is hereby granted, free of charge, to any person- obtaining a copy of this software and associated documentation- files (the "Software"), to deal in the Software without- restriction, including without limitation the rights to use,- copy, modify, merge, publish, distribute, sublicense, and/or sell- copies of the Software, and to permit persons to whom the- Software is furnished to do so, subject to the following- conditions:-- The above copyright notice and this permission notice shall be- included in all copies or substantial portions of the Software.-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR- OTHER DEALINGS IN THE SOFTWARE.--system-filepath LICENSE file:-- Copyright (c) 2010 John Millikin-- Permission is hereby granted, free of charge, to any person- obtaining a copy of this software and associated documentation- files (the "Software"), to deal in the Software without- restriction, including without limitation the rights to use,- copy, modify, merge, publish, distribute, sublicense, and/or sell- copies of the Software, and to permit persons to whom the- Software is furnished to do so, subject to the following- conditions:-- The above copyright notice and this permission notice shall be- included in all copies or substantial portions of the Software.-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR- OTHER DEALINGS IN THE SOFTWARE.- tagged LICENSE file: Copyright (c) 2009-2015 Edward Kmett@@ -4651,31 +4457,6 @@ DAMAGE. -temporary LICENSE file:-- Copyright (c) 2008, Maximilian Bolingbroke- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification, are permitted- provided that the following conditions are met:-- * Redistributions of source code must retain the above copyright notice, this list of- conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice, this list of- conditions and the following disclaimer in the documentation and/or other materials- provided with the distribution.- * Neither the name of Maximilian Bolingbroke nor the names of other contributors may be used to- endorse or promote products derived from this software without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- terminfo LICENSE file: Copyright 2007, Judah Jacobson.@@ -4870,33 +4651,6 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--turtle LICENSE file:-- Copyright (c) 2015 Gabriel Gonzalez- All rights reserved.-- Redistribution and use in source and binary forms, with or without modification,- are permitted provided that the following conditions are met:- * Redistributions of source code must retain the above copyright notice,- this list of conditions and the following disclaimer.- * Redistributions in binary form must reproduce the above copyright notice,- this list of conditions and the following disclaimer in the documentation- and/or other materials provided with the distribution.- * Neither the name of Gabriel Gonzalez nor the names of other contributors- may be used to endorse or promote products derived from this software- without specific prior written permission.-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. uniplate LICENSE file:
README.md view
@@ -1,6 +1,6 @@ [](http://purescript.org) -A small strongly typed programming language with expressive types that compiles to Javascript, written in and inspired by Haskell.+A small strongly typed programming language with expressive types that compiles to JavaScript, written in and inspired by Haskell. [](http://hackage.haskell.org/package/purescript) [](http://travis-ci.org/purescript/purescript)
+ app/Command/Bundle.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE RecordWildCards #-}++-- | Bundles compiled PureScript modules for the browser.+module Command.Bundle (command) where++import Data.Traversable (for)+import Data.Monoid ((<>))+import Data.Aeson (encode)+import Data.Maybe (isNothing)+import Control.Applicative+import Control.Monad+import Control.Monad.Error.Class+import Control.Monad.Trans.Except+import Control.Monad.IO.Class+import System.FilePath (takeDirectory, (</>), (<.>), takeFileName)+import System.FilePath.Glob (glob)+import System.Exit (exitFailure)+import System.IO (stderr, hPutStr, hPutStrLn)+import System.IO.UTF8 (readUTF8File, writeUTF8File)+import System.Directory (createDirectoryIfMissing, getCurrentDirectory)+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.UTF8 as BU8+import Language.PureScript.Bundle+import Options.Applicative (Parser)+import qualified Options.Applicative as Opts+import SourceMap+import SourceMap.Types++-- | Command line options.+data Options = Options+ { optionsInputFiles :: [FilePath]+ , optionsOutputFile :: Maybe FilePath+ , optionsEntryPoints :: [String]+ , optionsMainModule :: Maybe String+ , optionsNamespace :: String+ , optionsSourceMaps :: Bool+ } deriving Show++-- | The main application function.+-- This function parses the input files, performs dead code elimination, filters empty modules+-- and generates and prints the final Javascript bundle.+app :: (MonadError ErrorMessage m, MonadIO m) => Options -> m (Maybe SourceMapping, String)+app Options{..} = do+ inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles+ when (null inputFiles) . liftIO $ do+ hPutStrLn stderr "purs bundle: No input files."+ exitFailure+ when (isNothing optionsOutputFile && optionsSourceMaps == True) . liftIO $ do+ hPutStrLn stderr "purs bundle: Source maps only supported when output file specified."+ exitFailure++ input <- for inputFiles $ \filename -> do+ js <- liftIO (readUTF8File filename)+ mid <- guessModuleIdentifier filename+ length js `seq` return (mid, Just filename, js) -- evaluate readFile till EOF before returning, not to exhaust file handles++ let entryIds = map (`ModuleIdentifier` Regular) optionsEntryPoints++ currentDir <- liftIO getCurrentDirectory+ let outFile = if optionsSourceMaps then fmap (currentDir </>) optionsOutputFile else Nothing+ bundleSM input entryIds optionsMainModule optionsNamespace outFile++-- | Command line options parser.+options :: Parser Options+options = Options <$> some inputFile+ <*> optional outputFile+ <*> many entryPoint+ <*> optional mainModule+ <*> namespace+ <*> sourceMaps+ where+ inputFile :: Parser FilePath+ inputFile = Opts.strArgument $+ Opts.metavar "FILE"+ <> Opts.help "The input .js file(s)"++ outputFile :: Parser FilePath+ outputFile = Opts.strOption $+ Opts.short 'o'+ <> Opts.long "output"+ <> Opts.help "The output .js file"++ entryPoint :: Parser String+ entryPoint = Opts.strOption $+ Opts.short 'm'+ <> Opts.long "module"+ <> Opts.help "Entry point module name(s). All code which is not a transitive dependency of an entry point module will be removed."++ mainModule :: Parser String+ mainModule = Opts.strOption $+ Opts.long "main"+ <> Opts.help "Generate code to run the main method in the specified module."++ namespace :: Parser String+ namespace = Opts.strOption $+ Opts.short 'n'+ <> Opts.long "namespace"+ <> Opts.value "PS"+ <> Opts.showDefault+ <> Opts.help "Specify the namespace that PureScript modules will be exported to when running in the browser."++ sourceMaps :: Parser Bool+ sourceMaps = Opts.switch $+ Opts.long "source-maps"+ <> Opts.help "Whether to generate source maps for the bundle (requires --output)."++-- | Make it go.+command :: Opts.Parser (IO ())+command = run <$> (Opts.helper <*> options) where+ run :: Options -> IO ()+ run opts = do+ output <- runExceptT (app opts)+ case output of+ Left err -> do+ hPutStr stderr (unlines (printErrorMessage err))+ exitFailure+ Right (sourcemap, js) ->+ case optionsOutputFile opts of+ Just outputFile -> do+ createDirectoryIfMissing True (takeDirectory outputFile)+ case sourcemap of+ Just sm -> do+ writeUTF8File outputFile $ js ++ "\n//# sourceMappingURL=" ++ (takeFileName outputFile <.> "map") ++ "\n"+ writeUTF8File (outputFile <.> "map") $ BU8.toString . B.toStrict . encode $ generate sm+ Nothing -> writeUTF8File outputFile js+ Nothing -> putStrLn js
+ app/Command/Compile.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}++module Command.Compile (command) where++import Control.Applicative+import Control.Monad+import Control.Monad.Writer.Strict+import qualified Data.Aeson as A+import Data.Bool (bool)+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.UTF8 as BU8+import qualified Data.Map as M+import Data.Text (Text)+import qualified Language.PureScript as P+import Language.PureScript.Errors.JSON+import Language.PureScript.Make+import qualified Options.Applicative as Opts+import qualified System.Console.ANSI as ANSI+import System.Exit (exitSuccess, exitFailure)+import System.Directory (getCurrentDirectory)+import System.FilePath (makeRelative)+import System.FilePath.Glob (glob)+import System.IO (hPutStr, hPutStrLn, stderr)+import System.IO.UTF8 (readUTF8FileT)++data PSCMakeOptions = PSCMakeOptions+ { pscmInput :: [FilePath]+ , pscmOutputDir :: FilePath+ , pscmOpts :: P.Options+ , pscmUsePrefix :: Bool+ , pscmJSONErrors :: Bool+ }++-- | Argumnets: verbose, use JSON, warnings, errors+printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()+printWarningsAndErrors verbose False warnings errors = do+ cc <- bool Nothing (Just P.defaultCodeColor) <$> ANSI.hSupportsANSI stderr+ let ppeOpts = P.defaultPPEOptions { P.ppeCodeColor = cc, P.ppeFull = verbose }+ when (P.nonEmpty warnings) $+ hPutStrLn stderr (P.prettyPrintMultipleWarnings ppeOpts warnings)+ case errors of+ Left errs -> do+ hPutStrLn stderr (P.prettyPrintMultipleErrors ppeOpts errs)+ exitFailure+ Right _ -> return ()+printWarningsAndErrors verbose True warnings errors = do+ hPutStrLn stderr . BU8.toString . B.toStrict . A.encode $+ JSONResult (toJSONErrors verbose P.Warning warnings)+ (either (toJSONErrors verbose P.Error) (const []) errors)+ either (const exitFailure) (const (return ())) errors++compile :: PSCMakeOptions -> IO ()+compile PSCMakeOptions{..} = do+ pwd <- getCurrentDirectory+ input <- globWarningOnMisses (unless pscmJSONErrors . warnFileTypeNotFound) pscmInput+ when (null input && not pscmJSONErrors) $ do+ hPutStr stderr $ unlines [ "purs compile: No input files."+ , "Usage: For basic information, try the `--help' option."+ ]+ exitFailure+ moduleFiles <- readInput input+ (makeErrors, makeWarnings) <- runMake pscmOpts $ do+ ms <- P.parseModulesFromFiles (makeRelative pwd) moduleFiles+ let filePathMap = M.fromList $ map (\(fp, P.Module _ _ mn _ _) -> (mn, Right fp)) ms+ foreigns <- inferForeignModules filePathMap+ let makeActions = buildMakeActions pscmOutputDir filePathMap foreigns pscmUsePrefix+ P.make makeActions (map snd ms)+ printWarningsAndErrors (P.optionsVerboseErrors pscmOpts) pscmJSONErrors makeWarnings makeErrors+ exitSuccess++warnFileTypeNotFound :: String -> IO ()+warnFileTypeNotFound = hPutStrLn stderr . ("purs compile: No files found using pattern: " ++)++globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath]+globWarningOnMisses warn = concatMapM globWithWarning+ where+ globWithWarning pattern' = do+ paths <- glob pattern'+ when (null paths) $ warn pattern'+ return paths+ concatMapM f = fmap concat . mapM f++readInput :: [FilePath] -> IO [(FilePath, Text)]+readInput inputFiles = forM inputFiles $ \inFile -> (inFile, ) <$> readUTF8FileT inFile++inputFile :: Opts.Parser FilePath+inputFile = Opts.strArgument $+ Opts.metavar "FILE"+ <> Opts.help "The input .purs file(s)"++outputDirectory :: Opts.Parser FilePath+outputDirectory = Opts.strOption $+ Opts.short 'o'+ <> Opts.long "output"+ <> Opts.value "output"+ <> Opts.showDefault+ <> Opts.help "The output directory"++comments :: Opts.Parser Bool+comments = Opts.switch $+ Opts.short 'c'+ <> Opts.long "comments"+ <> Opts.help "Include comments in the generated code"++verboseErrors :: Opts.Parser Bool+verboseErrors = Opts.switch $+ Opts.short 'v'+ <> Opts.long "verbose-errors"+ <> Opts.help "Display verbose error messages"++noPrefix :: Opts.Parser Bool+noPrefix = Opts.switch $+ Opts.short 'p'+ <> Opts.long "no-prefix"+ <> Opts.help "Do not include comment header"++jsonErrors :: Opts.Parser Bool+jsonErrors = Opts.switch $+ Opts.long "json-errors"+ <> Opts.help "Print errors to stderr as JSON"++sourceMaps :: Opts.Parser Bool+sourceMaps = Opts.switch $+ Opts.long "source-maps"+ <> Opts.help "Generate source maps"++dumpCoreFn :: Opts.Parser Bool+dumpCoreFn = Opts.switch $+ Opts.long "dump-corefn"+ <> Opts.help "Dump the (functional) core representation of the compiled code at output/*/corefn.json"++options :: Opts.Parser P.Options+options = P.Options <$> verboseErrors+ <*> (not <$> comments)+ <*> sourceMaps+ <*> dumpCoreFn++pscMakeOptions :: Opts.Parser PSCMakeOptions+pscMakeOptions = PSCMakeOptions <$> many inputFile+ <*> outputDirectory+ <*> options+ <*> (not <$> noPrefix)+ <*> jsonErrors++command :: Opts.Parser (IO ())+command = compile <$> (Opts.helper <*> pscMakeOptions)
+ app/Command/Docs.hs view
@@ -0,0 +1,260 @@+{-# LANGUAGE TupleSections #-}++module Command.Docs (command, infoModList) where++import Protolude (ordNub)++import Command.Docs.Etags+import Command.Docs.Ctags+import Command.Docs.Html+import Control.Applicative+import Control.Arrow (first, second)+import Control.Category ((>>>))+import Control.Monad.Writer+import Control.Monad.Trans.Except (runExceptT)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Function (on)+import Data.List+import Data.Maybe (fromMaybe)+import Data.Tuple (swap)+import qualified Language.PureScript as P+import qualified Language.PureScript.Docs as D+import qualified Language.PureScript.Docs.AsMarkdown as D+import qualified Options.Applicative as Opts+import qualified Text.PrettyPrint.ANSI.Leijen as PP+import System.Directory (createDirectoryIfMissing)+import System.Exit (exitFailure)+import System.FilePath (takeDirectory)+import System.FilePath.Glob (glob)+import System.IO (hPutStrLn, hPrint, stderr)+import System.IO.UTF8 (readUTF8FileT, writeUTF8FileT)++-- | Available output formats+data Format+ = Markdown+ | Html+ | Ctags -- Output ctags symbol index suitable for use with vi+ | Etags -- Output etags symbol index suitable for use with emacs+ deriving (Show, Eq, Ord)++-- | Available methods of outputting Markdown documentation+data DocgenOutput+ = EverythingToStdOut+ | ToStdOut [P.ModuleName]+ | ToFiles [(P.ModuleName, FilePath)]+ deriving (Show)++data PSCDocsOptions = PSCDocsOptions+ { _pscdFormat :: Format+ , _pscdInputFiles :: [FilePath]+ , _pscdDocgen :: DocgenOutput+ }+ deriving (Show)++docgen :: PSCDocsOptions -> IO ()+docgen (PSCDocsOptions fmt inputGlob output) = do+ input <- concat <$> mapM glob inputGlob+ when (null input) $ do+ hPutStrLn stderr "purs docs: no input files."+ exitFailure++ case fmt of+ Etags -> dumpTags input dumpEtags+ Ctags -> dumpTags input dumpCtags+ Html -> do+ let outputDir = "./generated-docs" -- TODO: make this configurable+ ms <- parseAndConvert input+ let msHtml = map asHtml (D.primDocsModule : ms)+ createDirectoryIfMissing False outputDir+ writeHtmlModules outputDir msHtml++ Markdown -> do+ ms <- parseAndConvert input++ case output of+ EverythingToStdOut ->+ T.putStrLn (D.runDocs (D.modulesAsMarkdown ms))+ ToStdOut names -> do+ let (ms', missing) = takeByName ms names+ guardMissing missing+ T.putStrLn (D.runDocs (D.modulesAsMarkdown ms'))+ ToFiles names -> do+ let (ms', missing) = takeByName' ms names+ guardMissing missing++ let ms'' = groupBy ((==) `on` fst) . sortBy (compare `on` fst) $ map swap ms'+ forM_ ms'' $ \grp -> do+ let fp = fst (head grp)+ createDirectoryIfMissing True (takeDirectory fp)+ writeUTF8FileT fp (D.runDocs (D.modulesAsMarkdown (map snd grp)))++ where+ guardMissing [] = return ()+ guardMissing [mn] = do+ hPutStrLn stderr ("purs docs: error: unknown module \"" ++ T.unpack (P.runModuleName mn) ++ "\"")+ exitFailure+ guardMissing mns = do+ hPutStrLn stderr "purs docs: error: unknown modules:"+ forM_ mns $ \mn ->+ hPutStrLn stderr (" * " ++ T.unpack (P.runModuleName mn))+ exitFailure++ successOrExit :: Either P.MultipleErrors a -> IO a+ successOrExit act =+ case act of+ Right x ->+ return x+ Left err -> do+ hPutStrLn stderr $ P.prettyPrintMultipleErrors P.defaultPPEOptions err+ exitFailure++ takeByName = takeModulesByName D.modName+ takeByName' = takeModulesByName' D.modName++ parseAndConvert input =+ runExceptT (D.parseFilesInPackages input []+ >>= uncurry D.convertModulesInPackage)+ >>= successOrExit++-- |+-- Given a list of module names and a list of modules, return a list of modules+-- whose names appeared in the given name list, together with a list of names+-- for which no module could be found in the module list.+--+takeModulesByName :: (Eq n) => (m -> n) -> [m] -> [n] -> ([m], [n])+takeModulesByName getModuleName modules names =+ first (map fst) (takeModulesByName' getModuleName modules (map (,()) names))++-- |+-- Like takeModulesByName, but also keeps some extra information with each+-- module.+--+takeModulesByName' :: (Eq n) => (m -> n) -> [m] -> [(n, a)] -> ([(m, a)], [n])+takeModulesByName' getModuleName modules = foldl go ([], [])+ where+ go (ms, missing) (name, x) =+ case find ((== name) . getModuleName) modules of+ Just m -> ((m, x) : ms, missing)+ Nothing -> (ms, name : missing)++dumpTags :: [FilePath] -> ([(String, P.Module)] -> [String]) -> IO ()+dumpTags input renderTags = do+ e <- P.parseModulesFromFiles (fromMaybe "") <$> mapM (fmap (first Just) . parseFile) (ordNub input)+ case e of+ Left err -> do+ hPrint stderr err+ exitFailure+ Right ms ->+ ldump (renderTags (pairs ms))++ where+ pairs :: [(Maybe String, m)] -> [(String, m)]+ pairs = map (first (fromMaybe ""))++ ldump :: [String] -> IO ()+ ldump = mapM_ putStrLn++parseFile :: FilePath -> IO (FilePath, Text)+parseFile input = (,) input <$> readUTF8FileT input++inputFile :: Opts.Parser FilePath+inputFile = Opts.strArgument $+ Opts.metavar "FILE"+ <> Opts.help "The input .purs file(s)"++instance Read Format where+ readsPrec _ "etags" = [(Etags, "")]+ readsPrec _ "ctags" = [(Ctags, "")]+ readsPrec _ "markdown" = [(Markdown, "")]+ readsPrec _ "html" = [(Html, "")]+ readsPrec _ _ = []++format :: Opts.Parser Format+format = Opts.option Opts.auto $ Opts.value Markdown+ <> Opts.long "format"+ <> Opts.metavar "FORMAT"+ <> Opts.help "Set output FORMAT (markdown | html | etags | ctags)"++docgenModule :: Opts.Parser String+docgenModule = Opts.strOption $+ Opts.long "docgen"+ <> Opts.help "A list of module names which should appear in the output. This can optionally include file paths to write individual modules to, by separating with a colon ':'. For example, Prelude:docs/Prelude.md. This option may be specified multiple times."++pscDocsOptions :: Opts.Parser (Format, [FilePath], [String])+pscDocsOptions = (,,) <$> format <*> many inputFile <*> many docgenModule++parseDocgen :: [String] -> Either String DocgenOutput+parseDocgen [] = Right EverythingToStdOut+parseDocgen xs = go xs+ where+ go = intersperse " "+ >>> concat+ >>> words+ >>> map parseItem+ >>> combine++data DocgenOutputItem+ = IToStdOut P.ModuleName+ | IToFile (P.ModuleName, FilePath)++parseItem :: String -> DocgenOutputItem+parseItem s = case elemIndex ':' s of+ Just i ->+ s # splitAt i+ >>> first (P.moduleNameFromString . T.pack)+ >>> second (drop 1)+ >>> IToFile+ Nothing ->+ IToStdOut (P.moduleNameFromString (T.pack s))++ where+ infixr 1 #+ (#) = flip ($)++combine :: [DocgenOutputItem] -> Either String DocgenOutput+combine [] = Right EverythingToStdOut+combine (x:xs) = foldM go (initial x) xs+ where+ initial (IToStdOut m) = ToStdOut [m]+ initial (IToFile m) = ToFiles [m]++ go (ToStdOut ms) (IToStdOut m) = Right (ToStdOut (m:ms))+ go (ToFiles ms) (IToFile m) = Right (ToFiles (m:ms))+ go _ _ = Left "Can't mix module names and module name/file path pairs in the same invocation."++buildOptions :: (Format, [FilePath], [String]) -> IO PSCDocsOptions+buildOptions (fmt, input, mapping) =+ case parseDocgen mapping of+ Right mapping' -> return (PSCDocsOptions fmt input mapping')+ Left err -> do+ hPutStrLn stderr "purs docs: error in --docgen option:"+ hPutStrLn stderr (" " ++ err)+ exitFailure++command :: Opts.Parser (IO ())+command = (buildOptions >=> docgen) <$> (Opts.helper <*> pscDocsOptions)++infoModList :: Opts.InfoMod a+infoModList = Opts.fullDesc <> footerInfo where+ footerInfo = Opts.footerDoc $ Just examples++examples :: PP.Doc+examples =+ PP.vcat $ map PP.text+ [ "Examples:"+ , " print documentation for Data.List to stdout:"+ , " purs docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"+ , " --docgen Data.List"+ , ""+ , " write documentation for Data.List to docs/Data.List.md:"+ , " purs docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"+ , " --docgen Data.List:docs/Data.List.md"+ , ""+ , " write documentation for Data.List to docs/Data.List.md, and"+ , " documentation for Data.List.Lazy to docs/Data.List.Lazy.md:"+ , " purs docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"+ , " --docgen Data.List:docs/Data.List.md \\"+ , " --docgen Data.List.Lazy:docs/Data.List.Lazy.md"+ ]
+ app/Command/Docs/Ctags.hs view
@@ -0,0 +1,13 @@+module Command.Docs.Ctags (dumpCtags) where++import Command.Docs.Tags+import Data.List (sort)+import qualified Language.PureScript as P++dumpCtags :: [(String, P.Module)] -> [String]+dumpCtags = sort . concatMap renderModCtags++renderModCtags :: (String, P.Module) -> [String]+renderModCtags (path, mdl) = sort tagLines+ where tagLines = map tagLine $ tags mdl+ tagLine (name, line) = name ++ "\t" ++ path ++ "\t" ++ show line
+ app/Command/Docs/Etags.hs view
@@ -0,0 +1,13 @@+module Command.Docs.Etags (dumpEtags) where++import Command.Docs.Tags+import qualified Language.PureScript as P++dumpEtags :: [(String, P.Module)] -> [String]+dumpEtags = concatMap renderModEtags++renderModEtags :: (String, P.Module) -> [String]+renderModEtags (path, mdl) = ["\x0c", path ++ "," ++ show tagsLen] ++ tagLines+ where tagsLen = sum $ map length tagLines+ tagLines = map tagLine $ tags mdl+ tagLine (name, line) = "\x7f" ++ name ++ "\x01" ++ show line ++ ","
+ app/Command/Docs/Html.hs view
@@ -0,0 +1,181 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-}++module Command.Docs.Html+ ( asHtml+ , layout+ , writeHtmlModule+ , writeHtmlModules+ ) where++import Control.Applicative+import Control.Arrow ((&&&))+import Control.Monad.Writer+import Data.List (sort)+import Data.Text (Text)+import Data.Text.Lazy (toStrict)+import qualified Data.Text as T+import Data.FileEmbed (embedStringFile)+import qualified Language.PureScript as P+import qualified Language.PureScript.Docs as D+import qualified Language.PureScript.Docs.AsHtml as D+import Text.Blaze.Html5 (Html, (!), toMarkup)+import qualified Text.Blaze.Html5 as H+import qualified Text.Blaze.Html5.Attributes as A+import qualified Text.Blaze.Html.Renderer.Text as Blaze+import System.IO.UTF8 (writeUTF8FileT)+import System.FilePath.Glob (glob)+import System.Directory (removeFile)+import Version (versionString)++writeHtmlModules :: FilePath -> [(P.ModuleName, D.HtmlOutputModule Html)] -> IO ()+writeHtmlModules outputDir modules = do+ glob (outputDir <> "/*.html") >>= mapM_ removeFile+ let moduleList = sort $ map fst modules+ writeHtmlFile (outputDir ++ "/index.html") (renderIndexModule moduleList)+ mapM_ (writeHtmlModule outputDir . (fst &&& layout moduleList)) modules++asHtml :: D.Module -> (P.ModuleName, D.HtmlOutputModule Html)+asHtml m = D.moduleAsHtml (getHtmlRenderContext (D.modName m)) m++writeHtmlModule :: FilePath -> (P.ModuleName, Html) -> IO ()+writeHtmlModule outputDir (mn, html) = do+ let filepath = outputDir ++ "/" ++ T.unpack (P.runModuleName mn) ++ ".html"+ writeHtmlFile filepath html++writeHtmlFile :: FilePath -> Html -> IO ()+writeHtmlFile filepath =+ writeUTF8FileT filepath . toStrict . Blaze.renderHtml++getHtmlRenderContext :: P.ModuleName -> D.HtmlRenderContext+getHtmlRenderContext mn = D.HtmlRenderContext+ { D.currentModuleName = mn+ , D.buildDocLink = getLink mn+ , D.renderDocLink = renderLink+ , D.renderSourceLink = const Nothing+ }++-- TODO: try to combine this with the one in Docs.Types?+getLink :: P.ModuleName -> D.Namespace -> Text -> D.ContainingModule -> Maybe D.DocLink+getLink curMn namespace target containingMod = do+ location <- getLinkLocation+ return D.DocLink+ { D.linkLocation = location+ , D.linkTitle = target+ , D.linkNamespace = namespace+ }++ where+ getLinkLocation = builtinLinkLocation <|> normalLinkLocation++ normalLinkLocation = do+ case containingMod of+ D.ThisModule ->+ return D.SameModule+ D.OtherModule destMn ->+ -- This is OK because all modules count as 'local' for purs docs in+ -- html mode+ return $ D.LocalModule curMn destMn++ builtinLinkLocation = do+ let primMn = P.moduleNameFromString "Prim"+ guard $ containingMod == D.OtherModule primMn+ return $ D.BuiltinModule primMn++renderLink :: D.DocLink -> Text+renderLink l =+ case D.linkLocation l of+ D.SameModule ->+ ""+ D.LocalModule _ dest ->+ P.runModuleName dest <> ".html"+ D.DepsModule{} ->+ P.internalError "DepsModule: not implemented"+ D.BuiltinModule dest ->+ P.runModuleName dest <> ".html"++layout :: [P.ModuleName] -> (P.ModuleName, D.HtmlOutputModule Html) -> Html+layout moduleList (mn, htmlDocs) =+ basicLayout ("PureScript: " <> modName) $ do+ H.div ! A.class_ "page-title clearfix" $ do+ H.div ! A.class_ "page-title__label" $ "Module"+ H.h1 ! A.class_ "page-title__title" $ toMarkup modName++ H.div ! A.class_ "col col--main" $ do+ D.htmlOutputModuleLocals htmlDocs+ mapM_ renderReExports (D.htmlOutputModuleReExports htmlDocs)++ H.div ! A.class_ "col col--aside" $ do+ H.h3 "Modules"+ renderModuleList moduleList+ where+ modName = P.runModuleName mn++ renderReExports :: (D.InPackage P.ModuleName, Html) -> Html+ renderReExports (reExpFrom, html) = do+ H.h2 ! A.class_ "re-exports" $ do+ toMarkup ("Re-exports from " :: Text)+ H.a ! A.href (H.toValue (toText reExpFrom <> ".html")) $+ toMarkup (toText reExpFrom)+ html++ toText = P.runModuleName . D.ignorePackage++basicLayout :: Text -> Html -> Html+basicLayout title inner =+ H.docTypeHtml $ do+ H.head $ do+ H.meta ! A.charset "utf-8"+ H.meta ! A.httpEquiv "X-UA-Compatible" ! A.content "IE=edge"+ H.meta ! A.name "viewport" ! A.content "width=device-width, initial-scale=1"+ H.title (toMarkup title)++ H.link ! A.href "https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto:300,400,400i,700,700i"+ ! A.type_ "text/css" ! A.rel "stylesheet"+ H.style ! A.type_ "text/css" $+ toMarkup normalize_css+ H.style ! A.type_ "text/css" $+ toMarkup pursuit_css+ H.body $ do+ H.div ! A.class_ "everything-except-footer" $ do+ H.div ! A.class_ "top-banner clearfix" $ do+ H.div ! A.class_ "container clearfix" $ do+ H.div ! A.style inlineHeaderStyles $ do+ "PureScript API documentation"++ H.div ! A.class_ "top-banner__actions" $ do+ H.div ! A.class_ "top-banner__actions__item" $ do+ H.a ! A.href "index.html" $ "Index"++ H.main ! A.class_ "container clearfix" ! H.customAttribute "role" "main" $ do+ inner++ H.div ! A.class_ "footer clearfix" $+ H.p $ toMarkup $ "Generated by purs " <> versionString++ where+ -- Like Pursuit's .top-banner__logo except without the 'hover' styles+ inlineHeaderStyles = "float: left; font-size: 2.44em; font-weight: 300; line-height: 90px; margin: 0"++renderIndexModule :: [P.ModuleName] -> Html+renderIndexModule moduleList =+ basicLayout "PureScript API documentation" $ do+ H.div ! A.class_ "page-title clearfix" $ do+ H.h1 ! A.class_ "page-title__title" $ "Index"+ H.div ! A.class_ "col col--main" $ do+ renderModuleList moduleList++renderModuleList :: [P.ModuleName] -> Html+renderModuleList moduleList =+ H.ul $ mapM_ listItem moduleList++ where+ listItem mn = H.li $+ H.a ! A.href (H.toValue (P.runModuleName mn <> ".html")) $+ toMarkup (P.runModuleName mn)++normalize_css :: Text+normalize_css = $(embedStringFile "app/static/normalize.css")++pursuit_css :: Text+pursuit_css = $(embedStringFile "app/static/pursuit.css")
+ app/Command/Docs/Tags.hs view
@@ -0,0 +1,21 @@+module Command.Docs.Tags where++import Control.Arrow (first)+import qualified Data.Text as T+import qualified Language.PureScript as P++tags :: P.Module -> [(String, Int)]+tags = map (first T.unpack) . concatMap dtags . P.exportedDeclarations+ where dtags (P.PositionedDeclaration sp _ d) = map tag $ names d+ where tag name = (name, line)+ line = P.sourcePosLine $ P.spanStart sp+ dtags _ = []+ names (P.DataDeclaration _ name _ dcons) = P.runProperName name : consNames+ where consNames = map (\(cname, _) -> P.runProperName cname) dcons+ names (P.TypeDeclaration ident _) = [P.showIdent ident]+ names (P.ExternDeclaration ident _) = [P.showIdent ident]+ names (P.TypeSynonymDeclaration name _ _) = [P.runProperName name]+ names (P.TypeClassDeclaration name _ _ _ _) = [P.runProperName name]+ names (P.TypeInstanceDeclaration name _ _ _ _) = [P.showIdent name]+ names (P.ExternKindDeclaration name) = [P.runProperName name]+ names _ = []
+ app/Command/Hierarchy.hs view
@@ -0,0 +1,111 @@+-----------------------------------------------------------------------------+--+-- Module : Main+-- Copyright : (c) Hardy Jones 2014+-- License : MIT (http://opensource.org/licenses/MIT)+--+-- Maintainer : Hardy Jones <jones3.hardy@gmail.com>+-- Stability : experimental+-- Portability :+--+-- |+-- Generate Directed Graphs of PureScript TypeClasses+--+-----------------------------------------------------------------------------++{-# LANGUAGE TupleSections #-}+{-# LANGUAGE DataKinds #-}++module Command.Hierarchy (command) where++import Protolude (ordNub)++import Control.Applicative (optional)+import Control.Monad (unless)+import Data.List (intercalate, sort)+import Data.Foldable (for_)+import Data.Monoid ((<>))+import qualified Data.Text as T+import Options.Applicative (Parser)+import qualified Options.Applicative as Opts+import System.Directory (createDirectoryIfMissing)+import System.FilePath ((</>))+import System.FilePath.Glob (glob)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStr, stderr)+import System.IO.UTF8 (readUTF8FileT)+import qualified Language.PureScript as P++data HierarchyOptions = HierarchyOptions+ { _hierachyInput :: FilePath+ , _hierarchyOutput :: Maybe FilePath+ }++newtype SuperMap = SuperMap { _unSuperMap :: Either (P.ProperName 'P.ClassName) (P.ProperName 'P.ClassName, P.ProperName 'P.ClassName) }+ deriving Eq++instance Show SuperMap where+ show (SuperMap (Left sub)) = show sub+ show (SuperMap (Right (super, sub))) = show super ++ " -> " ++ show sub++instance Ord SuperMap where+ compare (SuperMap s) (SuperMap s') = getCls s `compare` getCls s'+ where+ getCls = either id snd++runModuleName :: P.ModuleName -> String+runModuleName (P.ModuleName pns) = intercalate "_" ((T.unpack . P.runProperName) `map` pns)++readInput :: [FilePath] -> IO (Either P.MultipleErrors [P.Module])+readInput paths = do+ content <- mapM (\path -> (path, ) <$> readUTF8FileT path) paths+ return $ map snd <$> P.parseModulesFromFiles id content++compile :: HierarchyOptions -> IO ()+compile (HierarchyOptions inputGlob mOutput) = do+ input <- glob inputGlob+ modules <- readInput input+ case modules of+ Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure+ Right ms -> do+ for_ ms $ \(P.Module _ _ moduleName decls _) ->+ let name = runModuleName moduleName+ tcs = filter P.isTypeClassDeclaration decls+ supers = sort . ordNub . filter (not . null) $ fmap superClasses tcs+ prologue = "digraph " ++ name ++ " {\n"+ body = intercalate "\n" (concatMap (fmap (\s -> " " ++ show s ++ ";")) supers)+ epilogue = "\n}"+ hier = prologue ++ body ++ epilogue+ in unless (null supers) $ case mOutput of+ Just output -> do+ createDirectoryIfMissing True output+ writeFile (output </> name) hier+ Nothing -> putStrLn hier+ exitSuccess++superClasses :: P.Declaration -> [SuperMap]+superClasses (P.TypeClassDeclaration sub _ supers@(_:_) _ _) =+ fmap (\(P.Constraint (P.Qualified _ super) _ _) -> SuperMap (Right (super, sub))) supers+superClasses (P.TypeClassDeclaration sub _ _ _ _) = [SuperMap (Left sub)]+superClasses (P.PositionedDeclaration _ _ decl) = superClasses decl+superClasses _ = []++inputFile :: Parser FilePath+inputFile = Opts.strArgument $+ Opts.metavar "FILE"+ <> Opts.value "main.purs"+ <> Opts.showDefault+ <> Opts.help "The input file to generate a hierarchy from"++outputFile :: Parser (Maybe FilePath)+outputFile = optional . Opts.strOption $+ Opts.short 'o'+ <> Opts.long "output"+ <> Opts.help "The output directory"++pscOptions :: Parser HierarchyOptions+pscOptions = HierarchyOptions <$> inputFile+ <*> outputFile++command :: Opts.Parser (IO ())+command = compile <$> (Opts.helper <*> pscOptions)
+ app/Command/Ide.hs view
@@ -0,0 +1,213 @@+-----------------------------------------------------------------------------+--+-- Module : Main+-- Description : The server accepting commands for psc-ide+-- Copyright : Christoph Hegemann 2016+-- License : MIT (http://opensource.org/licenses/MIT)+--+-- Maintainer : Christoph Hegemann <christoph.hegemann1337@gmail.com>+-- Stability : experimental+--+-- |+-- The server accepting commands for psc-ide+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE NoImplicitPrelude #-}++module Command.Ide (command) where++import Protolude++import qualified Data.Aeson as Aeson+import Control.Concurrent.STM+import "monad-logger" Control.Monad.Logger+import qualified Data.Text.IO as T+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Lazy.Char8 as BSL8+import GHC.IO.Exception (IOErrorType(..), IOException(..))+import Language.PureScript.Ide+import Language.PureScript.Ide.Command+import Language.PureScript.Ide.Util+import Language.PureScript.Ide.Error+import Language.PureScript.Ide.Types+import Language.PureScript.Ide.Watcher+import Network hiding (socketPort, accept)+import Network.BSD (getProtocolNumber)+import Network.Socket hiding (PortNumber, Type,+ sClose)+import qualified Options.Applicative as Opts+import System.Directory+import System.Info as SysInfo+import System.FilePath+import System.IO hiding (putStrLn, print)+import System.IO.Error (isEOFError)++listenOnLocalhost :: PortNumber -> IO Socket+listenOnLocalhost port = do+ proto <- getProtocolNumber "tcp"+ localhost <- inet_addr "127.0.0.1"+ bracketOnError+ (socket AF_INET Stream proto)+ sClose+ (\sock -> do+ setSocketOption sock ReuseAddr 1+ bind sock (SockAddrInet port localhost)+ listen sock maxListenQueue+ pure sock)++data ServerOptions = ServerOptions+ { _serverDirectory :: Maybe FilePath+ , _serverGlobs :: [FilePath]+ , _serverOutputPath :: FilePath+ , _serverPort :: PortNumber+ , _serverNoWatch :: Bool+ , _serverPolling :: Bool+ , _serverLoglevel :: IdeLogLevel+ } deriving (Show)++data ClientOptions = ClientOptions+ { clientPort :: PortID+ }++command :: Opts.Parser (IO ())+command = Opts.helper <*> subcommands where+ subcommands :: Opts.Parser (IO ())+ subcommands = (Opts.subparser . fold)+ [ Opts.command "server"+ (Opts.info (fmap server serverOptions)+ (Opts.progDesc "Start a server process"))+ , Opts.command "client"+ (Opts.info (fmap client clientOptions)+ (Opts.progDesc "Connect to a running server"))+ ]++ client :: ClientOptions -> IO ()+ client ClientOptions{..} = do+ hSetEncoding stdin utf8+ hSetEncoding stdout utf8+ let handler (SomeException e) = do+ T.putStrLn ("Couldn't connect to purs ide server on port " <> show clientPort <> ":")+ print e+ exitFailure+ h <- connectTo "127.0.0.1" clientPort `catch` handler+ T.hPutStrLn h =<< T.getLine+ BS8.putStrLn =<< BS8.hGetLine h+ hFlush stdout+ hClose h++ clientOptions :: Opts.Parser ClientOptions+ clientOptions = ClientOptions . PortNumber . fromIntegral <$>+ Opts.option Opts.auto (Opts.long "port" <> Opts.short 'p' <> Opts.value (4242 :: Integer))++ server :: ServerOptions -> IO ()+ server opts'@(ServerOptions dir globs outputPath port noWatch polling logLevel) = do+ when (logLevel == LogDebug || logLevel == LogAll)+ (putText "Parsed Options:" *> print opts')+ maybe (pure ()) setCurrentDirectory dir+ ideState <- newTVarIO emptyIdeState+ cwd <- getCurrentDirectory+ let fullOutputPath = cwd </> outputPath++ unlessM (doesDirectoryExist fullOutputPath) $ do+ putText "Your output directory didn't exist. This usually means you didn't compile your project yet."+ putText "psc-ide needs you to compile your project (for example by running pulp build)"++ unless noWatch $+ void (forkFinally (watcher polling ideState fullOutputPath) print)+ let conf = Configuration {confLogLevel = logLevel, confOutputPath = outputPath, confGlobs = globs}+ env = IdeEnvironment {ideStateVar = ideState, ideConfiguration = conf}+ startServer port env++ serverOptions :: Opts.Parser ServerOptions+ serverOptions =+ ServerOptions+ <$> optional (Opts.strOption (Opts.long "directory" `mappend` Opts.short 'd'))+ <*> many (Opts.argument Opts.str (Opts.metavar "Source GLOBS..."))+ <*> Opts.strOption (Opts.long "output-directory" `mappend` Opts.value "output/")+ <*> (fromIntegral <$>+ Opts.option Opts.auto (Opts.long "port" `mappend` Opts.short 'p' `mappend` Opts.value (4242 :: Integer)))+ <*> Opts.switch (Opts.long "no-watch")+ <*> flipIfWindows (Opts.switch (Opts.long "polling"))+ <*> (parseLogLevel <$> Opts.strOption+ (Opts.long "log-level"+ `mappend` Opts.value ""+ `mappend` Opts.help "One of \"debug\", \"perf\", \"all\" or \"none\""))++ parseLogLevel s = case s of+ "debug" -> LogDebug+ "perf" -> LogPerf+ "all" -> LogAll+ "none" -> LogNone+ _ -> LogDefault++ -- polling is the default on Windows and the flag turns it off. See+ -- #2209 and #2414 for explanations+ flipIfWindows = map (if SysInfo.os == "mingw32" then not else identity)++startServer :: PortNumber -> IdeEnvironment -> IO ()+startServer port env = withSocketsDo $ do+ sock <- listenOnLocalhost port+ runLogger (confLogLevel (ideConfiguration env)) (runReaderT (forever (loop sock)) env)+ where+ loop :: (Ide m, MonadLogger m) => Socket -> m ()+ loop sock = do+ accepted <- runExceptT (acceptCommand sock)+ case accepted of+ Left err -> $(logError) err+ Right (cmd, h) -> do+ case decodeT cmd of+ Just cmd' -> do+ let message duration =+ "Command " <> commandName cmd'+ <> " took "+ <> displayTimeSpec duration+ result <- logPerf message (runExceptT (handleCommand cmd'))+ -- $(logDebug) ("Answer was: " <> T.pack (show result))+ liftIO (hFlush stdout)+ case result of+ Right r -> liftIO $ catchGoneHandle (BSL8.hPutStrLn h (Aeson.encode r))+ Left err -> liftIO $ catchGoneHandle (BSL8.hPutStrLn h (Aeson.encode err))+ Nothing -> do+ $(logError) ("Parsing the command failed. Command: " <> cmd)+ liftIO $ do+ catchGoneHandle (T.hPutStrLn h (encodeT (GeneralError "Error parsing Command.")))+ hFlush stdout+ liftIO $ catchGoneHandle (hClose h)++catchGoneHandle :: IO () -> IO ()+catchGoneHandle =+ handle (\e -> case e of+ IOError { ioe_type = ResourceVanished } ->+ putText ("[Error] psc-ide-server tried interact with the handle, but the connection was already gone.")+ _ -> throwIO e)++acceptCommand :: (MonadIO m, MonadLogger m, MonadError Text m)+ => Socket -> m (Text, Handle)+acceptCommand sock = do+ h <- acceptConnection+ $(logDebug) "Accepted a connection"+ cmd' <- liftIO (catchJust+ -- this means that the connection was+ -- terminated without receiving any input+ (\e -> if isEOFError e then Just () else Nothing)+ (Just <$> T.hGetLine h)+ (const (pure Nothing)))+ case cmd' of+ Nothing -> throwError "Connection was closed before any input arrived"+ Just cmd -> do+ $(logDebug) ("Received command: " <> cmd)+ pure (cmd, h)+ where+ acceptConnection = liftIO $ do+ -- Use low level accept to prevent accidental reverse name resolution+ (s,_) <- accept sock+ h <- socketToHandle s ReadWriteMode+ hSetEncoding h utf8+ hSetBuffering h LineBuffering+ pure h
+ app/Command/Publish.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE OverloadedStrings #-}++module Command.Publish (command) where++import Control.Monad.IO.Class (liftIO)+import qualified Data.Aeson as A+import qualified Data.ByteString.Lazy.Char8 as BL+import Data.Monoid ((<>))+import Data.Time.Clock (getCurrentTime)+import Data.Version (Version(..))+import Language.PureScript.Publish+import Language.PureScript.Publish.ErrorsWarnings+import Options.Applicative (Parser)+import qualified Options.Applicative as Opts++manifestPath :: Parser FilePath+manifestPath = Opts.strOption $+ Opts.long "manifest"+ <> Opts.metavar "FILE"+ <> Opts.help "The package manifest file"++resolutionsPath :: Parser FilePath+resolutionsPath = Opts.strOption $+ Opts.long "resolutions"+ <> Opts.metavar "FILE"+ <> Opts.help "The resolutions file"++dryRun :: Parser Bool+dryRun = Opts.switch $+ Opts.long "dry-run"+ <> Opts.help "Produce no output, and don't require a tagged version to be checked out."++dryRunOptions :: PublishOptions+dryRunOptions = defaultPublishOptions+ { publishGetVersion = return dummyVersion+ , publishWorkingTreeDirty = warn DirtyWorkingTree_Warn+ , publishGetTagTime = const (liftIO getCurrentTime)+ }+ where dummyVersion = ("0.0.0", Version [0,0,0] [])++command :: Opts.Parser (IO ())+command = publish <$> manifestPath <*> resolutionsPath <*> (Opts.helper <*> dryRun)++publish :: FilePath -> FilePath -> Bool -> IO ()+publish manifestFile resolutionsFile isDryRun =+ if isDryRun+ then do+ _ <- unsafePreparePackage manifestFile resolutionsFile dryRunOptions+ putStrLn "Dry run completed, no errors."+ else do+ pkg <- unsafePreparePackage manifestFile resolutionsFile defaultPublishOptions+ BL.putStrLn (A.encode pkg)
+ app/Command/REPL.hs view
@@ -0,0 +1,379 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-}++module Command.REPL (command) where++import Prelude ()+import Prelude.Compat+import Control.Applicative (many, (<|>))+import Control.Concurrent (forkIO)+import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar,+ tryPutMVar)+import Control.Concurrent.STM (TVar, atomically, newTVarIO, writeTVar,+ readTVarIO,+ TChan, newBroadcastTChanIO, dupTChan,+ readTChan, writeTChan)+import Control.Exception (fromException)+import Control.Monad+import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Class+import Control.Monad.Trans.Except (ExceptT(..), runExceptT)+import Control.Monad.Trans.State.Strict (StateT, evalStateT)+import Control.Monad.Trans.Reader (ReaderT, runReaderT)+import Data.FileEmbed (embedStringFile)+import Data.Foldable (for_)+import Data.Monoid ((<>))+import Data.String (IsString(..))+import Data.Text (Text, unpack)+import Data.Traversable (for)+import qualified Language.PureScript as P+import qualified Language.PureScript.Bundle as Bundle+import Language.PureScript.Interactive+import Network.HTTP.Types.Header (hContentType, hCacheControl,+ hPragma, hExpires)+import Network.HTTP.Types.Status (status200, status404, status503)+import qualified Network.Wai as Wai+import qualified Network.Wai.Handler.Warp as Warp+import qualified Network.Wai.Handler.WebSockets as WS+import qualified Network.WebSockets as WS+import qualified Options.Applicative as Opts+import System.Console.Haskeline+import System.IO.UTF8 (readUTF8File)+import System.Exit+import System.Directory (doesFileExist, getCurrentDirectory)+import System.FilePath ((</>))+import System.FilePath.Glob (glob)+import System.Process (readProcessWithExitCode)++-- | Command line options+data PSCiOptions = PSCiOptions+ { psciInputFile :: [FilePath]+ , psciBackend :: Backend+ }++inputFile :: Opts.Parser FilePath+inputFile = Opts.strArgument $+ Opts.metavar "FILE"+ <> Opts.help "Optional .purs files to load on start"++nodePathOption :: Opts.Parser (Maybe FilePath)+nodePathOption = Opts.optional . Opts.strOption $+ Opts.metavar "FILE"+ <> Opts.long "node-path"+ <> Opts.help "Path to the Node executable"++nodeFlagsOption :: Opts.Parser [String]+nodeFlagsOption = Opts.option parser $+ Opts.long "node-opts"+ <> Opts.metavar "OPTS"+ <> Opts.value []+ <> Opts.help "Flags to pass to node, separated by spaces"+ where+ parser = words <$> Opts.str++port :: Opts.Parser Int+port = Opts.option Opts.auto $+ Opts.long "port"+ <> Opts.short 'p'+ <> Opts.help "The web server port"++backend :: Opts.Parser Backend+backend =+ (browserBackend <$> port)+ <|> (nodeBackend <$> nodePathOption <*> nodeFlagsOption)++psciOptions :: Opts.Parser PSCiOptions+psciOptions = PSCiOptions <$> many inputFile+ <*> backend++-- | Parses the input and returns either a command, or an error as a 'String'.+getCommand :: forall m. MonadException m => InputT m (Either String (Maybe Command))+getCommand = handleInterrupt (return (Right Nothing)) $ do+ line <- withInterrupt $ getInputLine "> "+ case line of+ Nothing -> return (Right (Just QuitPSCi)) -- Ctrl-D when input is empty+ Just "" -> return (Right Nothing)+ Just s -> return . fmap Just $ parseCommand s++pasteMode :: forall m. MonadException m => InputT m (Either String Command)+pasteMode =+ parseCommand <$> go []+ where+ go :: [String] -> InputT m String+ go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine "… "++-- | Make a JavaScript bundle for the browser.+bundle :: IO (Either Bundle.ErrorMessage String)+bundle = runExceptT $ do+ inputFiles <- liftIO (glob (".psci_modules" </> "node_modules" </> "*" </> "*.js"))+ input <- for inputFiles $ \filename -> do+ js <- liftIO (readUTF8File filename)+ mid <- Bundle.guessModuleIdentifier filename+ length js `seq` return (mid, js)+ Bundle.bundle input [] Nothing "PSCI"++indexJS :: IsString string => string+indexJS = $(embedStringFile "app/static/index.js")++indexPage :: IsString string => string+indexPage = $(embedStringFile "app/static/index.html")++-- | All of the functions required to implement a PSCi backend+data Backend = forall state. Backend+ { _backendSetup :: IO state+ -- ^ Initialize, and call the continuation when the backend is ready+ , _backendEval :: state -> String -> IO ()+ -- ^ Evaluate JavaScript code+ , _backendReload :: state -> IO ()+ -- ^ Reload the compiled code+ , _backendShutdown :: state -> IO ()+ -- ^ Shut down the backend+ }++-- | Commands which can be sent to the browser+data BrowserCommand+ = Eval (MVar String)+ -- ^ Evaluate the latest JS+ | Refresh+ -- ^ Refresh the page++-- | State for the browser backend+data BrowserState = BrowserState+ { browserCommands :: TChan BrowserCommand+ -- ^ A channel which receives data when the compiled JS has+ -- been updated+ , browserShutdownNotice :: MVar ()+ -- ^ An MVar which becomes full when the server should shut down+ , browserIndexJS :: TVar (Maybe String)+ -- ^ A TVar holding the latest compiled JS+ , browserBundleJS :: TVar (Maybe String)+ -- ^ A TVar holding the latest bundled JS+ }++browserBackend :: Int -> Backend+browserBackend serverPort = Backend setup evaluate reload shutdown+ where+ setup :: IO BrowserState+ setup = do+ shutdownVar <- newEmptyMVar+ cmdChan <- newBroadcastTChanIO+ indexJs <- newTVarIO Nothing+ bundleJs <- newTVarIO Nothing++ let+ handleWebsocket :: WS.PendingConnection -> IO ()+ handleWebsocket pending = do+ conn <- WS.acceptRequest pending+ -- Fork a thread to keep the connection alive+ WS.forkPingThread conn 10+ -- Clone the command channel+ cmdChanCopy <- atomically $ dupTChan cmdChan+ -- Listen for commands+ forever $ do+ cmd <- atomically $ readTChan cmdChanCopy+ case cmd of+ Eval resultVar -> void $ do+ WS.sendTextData conn ("eval" :: Text)+ result <- WS.receiveData conn+ -- With many connected clients, all but one of+ -- these attempts will fail.+ tryPutMVar resultVar (unpack result)+ Refresh ->+ WS.sendTextData conn ("reload" :: Text)++ shutdownHandler :: IO () -> IO ()+ shutdownHandler stopServer = void . forkIO $ do+ () <- takeMVar shutdownVar+ stopServer++ onException :: Maybe Wai.Request -> SomeException -> IO ()+ onException req ex+ | Just (_ :: WS.ConnectionException) <- fromException ex+ = return () -- ignore websocket disconnects+ | otherwise = Warp.defaultOnException req ex++ staticServer :: Wai.Application+ staticServer req respond =+ case Wai.pathInfo req of+ [] ->+ respond $ Wai.responseLBS status200+ [(hContentType, "text/html")]+ indexPage+ ["js", "index.js"] ->+ respond $ Wai.responseLBS status200+ [(hContentType, "application/javascript")]+ indexJS+ ["js", "latest.js"] -> do+ may <- readTVarIO indexJs+ case may of+ Nothing ->+ respond $ Wai.responseLBS status503 [] "Service not available"+ Just js ->+ respond $ Wai.responseLBS status200+ [ (hContentType, "application/javascript")+ , (hCacheControl, "no-cache, no-store, must-revalidate")+ , (hPragma, "no-cache")+ , (hExpires, "0")+ ]+ (fromString js)+ ["js", "bundle.js"] -> do+ may <- readTVarIO bundleJs+ case may of+ Nothing ->+ respond $ Wai.responseLBS status503 [] "Service not available"+ Just js ->+ respond $ Wai.responseLBS status200+ [ (hContentType, "application/javascript")]+ (fromString js)+ _ -> respond $ Wai.responseLBS status404 [] "Not found"++ let browserState = BrowserState cmdChan shutdownVar indexJs bundleJs+ createBundle browserState++ putStrLn $ "Serving http://localhost:" <> show serverPort <> "/. Waiting for connections..."+ _ <- forkIO $ Warp.runSettings ( Warp.setInstallShutdownHandler shutdownHandler+ . Warp.setPort serverPort+ . Warp.setOnException onException+ $ Warp.defaultSettings+ ) $+ WS.websocketsOr WS.defaultConnectionOptions+ handleWebsocket+ staticServer+ return browserState++ createBundle :: BrowserState -> IO ()+ createBundle state = do+ putStrLn "Bundling JavaScript..."+ ejs <- bundle+ case ejs of+ Left err -> do+ putStrLn (unlines (Bundle.printErrorMessage err))+ exitFailure+ Right js ->+ atomically $ writeTVar (browserBundleJS state) (Just js)++ reload :: BrowserState -> IO ()+ reload state = do+ createBundle state+ atomically $ writeTChan (browserCommands state) Refresh++ shutdown :: BrowserState -> IO ()+ shutdown state = putMVar (browserShutdownNotice state) ()++ evaluate :: BrowserState -> String -> IO ()+ evaluate state js = liftIO $ do+ resultVar <- newEmptyMVar+ atomically $ do+ writeTVar (browserIndexJS state) (Just js)+ writeTChan (browserCommands state) (Eval resultVar)+ result <- takeMVar resultVar+ putStrLn result++nodeBackend :: Maybe FilePath -> [String] -> Backend+nodeBackend nodePath nodeArgs = Backend setup eval reload shutdown+ where+ setup :: IO ()+ setup = return ()++ eval :: () -> String -> IO ()+ eval _ _ = do+ writeFile indexFile "require('$PSCI')['$main']();"+ process <- maybe findNodeProcess (pure . pure) nodePath+ result <- traverse (\node -> readProcessWithExitCode node (nodeArgs ++ [indexFile]) "") process+ case result of+ Just (ExitSuccess, out, _) -> putStrLn out+ Just (ExitFailure _, _, err) -> putStrLn err+ Nothing -> putStrLn "Couldn't find node.js"++ reload :: () -> IO ()+ reload _ = return ()++ shutdown :: () -> IO ()+ shutdown _ = return ()++options :: Opts.Parser PSCiOptions+options = Opts.helper <*> psciOptions++-- | Get command line options and drop into the REPL+command :: Opts.Parser (IO ())+command = loop <$> options+ where+ loop :: PSCiOptions -> IO ()+ loop PSCiOptions{..} = do+ inputFiles <- concat <$> traverse glob psciInputFile+ e <- runExceptT $ do+ modules <- ExceptT (loadAllModules inputFiles)+ when (null modules) . liftIO $ do+ putStr noInputMessage+ exitFailure+ unless (supportModuleIsDefined (map snd modules)) . liftIO $ do+ putStr supportModuleMessage+ exitFailure+ (externs, env) <- ExceptT . runMake . make $ modules+ return (modules, externs, env)+ case psciBackend of+ Backend setup eval reload (shutdown :: state -> IO ()) ->+ case e of+ Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure+ Right (modules, externs, env) -> do+ historyFilename <- getHistoryFilename+ let settings = defaultSettings { historyFile = Just historyFilename }+ initialState = PSCiState [] [] (zip (map snd modules) externs)+ config = PSCiConfig inputFiles env+ runner = flip runReaderT config+ . flip evalStateT initialState+ . runInputT (setComplete completion settings)++ handleCommand' :: state -> Command -> StateT PSCiState (ReaderT PSCiConfig IO) ()+ handleCommand' state = handleCommand (liftIO . eval state) (liftIO (reload state))++ go :: state -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()+ go state = do+ c <- getCommand+ case c of+ Left err -> outputStrLn err >> go state+ Right Nothing -> go state+ Right (Just PasteLines) -> do+ c' <- pasteMode+ case c' of+ Left err -> outputStrLn err >> go state+ Right c'' -> handleCommandWithInterrupts state c''+ Right (Just QuitPSCi) -> do+ outputStrLn quitMessage+ liftIO $ shutdown state+ Right (Just c') -> handleCommandWithInterrupts state c'++ loadUserConfig :: state -> StateT PSCiState (ReaderT PSCiConfig IO) ()+ loadUserConfig state = do+ configFile <- (</> ".purs-repl") <$> liftIO getCurrentDirectory+ exists <- liftIO $ doesFileExist configFile+ when exists $ do+ ls <- lines <$> liftIO (readUTF8File configFile)+ for_ ls $ \l -> do+ liftIO (putStrLn l)+ case parseCommand l of+ Left err -> liftIO (putStrLn err >> exitFailure)+ Right cmd@Import{} -> handleCommand' state cmd+ Right _ -> liftIO (putStrLn "The .purs-repl file only supports import declarations")++ handleCommandWithInterrupts+ :: state+ -> Command+ -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()+ handleCommandWithInterrupts state cmd = do+ handleInterrupt (outputStrLn "Interrupted.")+ (withInterrupt (lift (handleCommand' state cmd)))+ go state++ putStrLn prologueMessage+ backendState <- setup+ runner (lift (loadUserConfig backendState) >> go backendState)
+ app/Main.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}++module Main where++import qualified Command.Bundle as Bundle+import qualified Command.Compile as Compile+import qualified Command.Docs as Docs+import qualified Command.Hierarchy as Hierarchy+import qualified Command.Ide as Ide+import qualified Command.Publish as Publish+import qualified Command.REPL as REPL+import Data.Foldable (fold)+import Data.Monoid ((<>))+import qualified Options.Applicative as Opts+import qualified System.IO as IO+import Version (versionString)+++main :: IO ()+main = do+ IO.hSetEncoding IO.stdout IO.utf8+ IO.hSetEncoding IO.stderr IO.utf8+ cmd <- Opts.execParser opts+ cmd+ where+ opts = Opts.info (versionInfo <*> Opts.helper <*> commands) infoModList+ infoModList = Opts.fullDesc <> headerInfo <> footerInfo+ headerInfo = Opts.progDesc "The PureScript compiler and tools"+ footerInfo = Opts.footer $ "purs " ++ versionString++ versionInfo :: Opts.Parser (a -> a)+ versionInfo = Opts.abortOption (Opts.InfoMsg versionString) $+ Opts.long "version" <> Opts.help "Show the version number" <> Opts.hidden++ commands :: Opts.Parser (IO ())+ commands =+ (Opts.subparser . fold)+ [ Opts.command "bundle"+ (Opts.info Bundle.command+ (Opts.progDesc "Bundle compiled PureScript modules for the browser"))+ , Opts.command "compile"+ (Opts.info Compile.command+ (Opts.progDesc "Compile PureScript source files"))+ , Opts.command "docs"+ (Opts.info Docs.command+ (Opts.progDesc "Generate Markdown documentation from PureScript source files" <> Docs.infoModList))+ , Opts.command "hierarchy"+ (Opts.info Hierarchy.command+ (Opts.progDesc "Generate a GraphViz directed graph of PureScript type classes"))+ , Opts.command "ide"+ (Opts.info Ide.command+ (Opts.progDesc "Start or query an IDE server process"))+ , Opts.command "publish"+ (Opts.info Publish.command+ (Opts.progDesc "Generates documentation packages for upload to Pursuit"))+ , Opts.command "repl"+ (Opts.info REPL.command+ (Opts.progDesc "Enter the interactive mode (PSCi)"))+ ]
+ app/Version.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell #-}++module Version where++import Data.Version (showVersion)+import Paths_purescript as Paths++#ifndef RELEASE+import qualified Development.GitRev as GitRev+#endif++versionString :: String+versionString = showVersion Paths.version ++ extra+ where+#ifdef RELEASE+ extra = ""+#else+ extra = " [development build; commit: " ++ $(GitRev.gitHash) ++ dirty ++ "]"+ dirty+ | $(GitRev.gitDirty) = " DIRTY"+ | otherwise = ""+#endif
+ app/static/index.html view
@@ -0,0 +1,10 @@+<!DOCTYPE html>+<html>+<head>+ <title>PureScript Interactive</title>+ <script src='js/bundle.js'></script>+ <script src='js/index.js'></script>+</head>+<body>+</body>+</html>
+ app/static/index.js view
@@ -0,0 +1,63 @@+var get = function get(uri, callback, onError) {+ var request = new XMLHttpRequest();+ request.addEventListener('load', function() {+ callback(request.responseText);+ });+ request.addEventListener('error', onError);+ request.open('GET', uri);+ request.send();+};+var evaluate = function evaluate(js) {+ var buffer = [];+ // Save the old console.log function+ var oldLog = console.log;+ console.log = function(s) {+ // Push log output into a temporary buffer+ // which will be returned to PSCi.+ buffer.push(s);+ };+ // Replace any require(...) statements with lookups on the PSCI object.+ var replaced = js.replace(/require\("[^"]*"\)/g, function(s) {+ return "PSCI['" + s.substring(12, s.length - 2) + "']";+ });+ // Wrap the module and evaluate it.+ var wrapped =+ [ 'var module = {};'+ , '(function(module) {'+ , replaced+ , '})(module);'+ , 'return module.exports["$main"] && module.exports["$main"]();'+ ].join('\n');+ new Function(wrapped)();+ // Restore console.log+ console.log = oldLog;+ return buffer.join('\n');+};+window.onload = function() {+ var socket = new WebSocket('ws://localhost:' + location.port);+ var evalNext = function reload() {+ get('js/latest.js', function(response) {+ try {+ var result = evaluate(response);+ socket.send(result);+ } catch (ex) {+ socket.send(ex.stack);+ }+ }, function(err) {+ socket.send('Error sending JavaScript');+ });+ };+ socket.onopen = function() {+ console.log('Connected');+ socket.onmessage = function(event) {+ switch (event.data) {+ case 'eval':+ evalNext();+ break;+ case 'reload':+ location.reload();+ break;+ }+ };+ };+};
+ app/static/normalize.css view
@@ -0,0 +1,427 @@+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */++/**+ * 1. Set default font family to sans-serif.+ * 2. Prevent iOS text size adjust after orientation change, without disabling+ * user zoom.+ */++html {+ font-family: sans-serif; /* 1 */+ -ms-text-size-adjust: 100%; /* 2 */+ -webkit-text-size-adjust: 100%; /* 2 */+}++/**+ * Remove default margin.+ */++body {+ margin: 0;+}++/* HTML5 display definitions+ ========================================================================== */++/**+ * Correct `block` display not defined for any HTML5 element in IE 8/9.+ * Correct `block` display not defined for `details` or `summary` in IE 10/11+ * and Firefox.+ * Correct `block` display not defined for `main` in IE 11.+ */++article,+aside,+details,+figcaption,+figure,+footer,+header,+hgroup,+main,+menu,+nav,+section,+summary {+ display: block;+}++/**+ * 1. Correct `inline-block` display not defined in IE 8/9.+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.+ */++audio,+canvas,+progress,+video {+ display: inline-block; /* 1 */+ vertical-align: baseline; /* 2 */+}++/**+ * Prevent modern browsers from displaying `audio` without controls.+ * Remove excess height in iOS 5 devices.+ */++audio:not([controls]) {+ display: none;+ height: 0;+}++/**+ * Address `[hidden]` styling not present in IE 8/9/10.+ * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.+ */++[hidden],+template {+ display: none;+}++/* Links+ ========================================================================== */++/**+ * Remove the gray background color from active links in IE 10.+ */++a {+ background-color: transparent;+}++/**+ * Improve readability when focused and also mouse hovered in all browsers.+ */++a:active,+a:hover {+ outline: 0;+}++/* Text-level semantics+ ========================================================================== */++/**+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.+ */++abbr[title] {+ border-bottom: 1px dotted;+}++/**+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.+ */++b,+strong {+ font-weight: bold;+}++/**+ * Address styling not present in Safari and Chrome.+ */++dfn {+ font-style: italic;+}++/**+ * Address variable `h1` font-size and margin within `section` and `article`+ * contexts in Firefox 4+, Safari, and Chrome.+ */++h1 {+ font-size: 2em;+ margin: 0.67em 0;+}++/**+ * Address styling not present in IE 8/9.+ */++mark {+ background: #ff0;+ color: #000;+}++/**+ * Address inconsistent and variable font size in all browsers.+ */++small {+ font-size: 80%;+}++/**+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.+ */++sub,+sup {+ font-size: 75%;+ line-height: 0;+ position: relative;+ vertical-align: baseline;+}++sup {+ top: -0.5em;+}++sub {+ bottom: -0.25em;+}++/* Embedded content+ ========================================================================== */++/**+ * Remove border when inside `a` element in IE 8/9/10.+ */++img {+ border: 0;+}++/**+ * Correct overflow not hidden in IE 9/10/11.+ */++svg:not(:root) {+ overflow: hidden;+}++/* Grouping content+ ========================================================================== */++/**+ * Address margin not present in IE 8/9 and Safari.+ */++figure {+ margin: 1em 40px;+}++/**+ * Address differences between Firefox and other browsers.+ */++hr {+ -moz-box-sizing: content-box;+ box-sizing: content-box;+ height: 0;+}++/**+ * Contain overflow in all browsers.+ */++pre {+ overflow: auto;+}++/**+ * Address odd `em`-unit font size rendering in all browsers.+ */++code,+kbd,+pre,+samp {+ font-family: monospace, monospace;+ font-size: 1em;+}++/* Forms+ ========================================================================== */++/**+ * Known limitation: by default, Chrome and Safari on OS X allow very limited+ * styling of `select`, unless a `border` property is set.+ */++/**+ * 1. Correct color not being inherited.+ * Known issue: affects color of disabled elements.+ * 2. Correct font properties not being inherited.+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.+ */++button,+input,+optgroup,+select,+textarea {+ color: inherit; /* 1 */+ font: inherit; /* 2 */+ margin: 0; /* 3 */+}++/**+ * Address `overflow` set to `hidden` in IE 8/9/10/11.+ */++button {+ overflow: visible;+}++/**+ * Address inconsistent `text-transform` inheritance for `button` and `select`.+ * All other form control elements do not inherit `text-transform` values.+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.+ * Correct `select` style inheritance in Firefox.+ */++button,+select {+ text-transform: none;+}++/**+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`+ * and `video` controls.+ * 2. Correct inability to style clickable `input` types in iOS.+ * 3. Improve usability and consistency of cursor style between image-type+ * `input` and others.+ */++button,+html input[type="button"], /* 1 */+input[type="reset"],+input[type="submit"] {+ -webkit-appearance: button; /* 2 */+ cursor: pointer; /* 3 */+}++/**+ * Re-set default cursor for disabled elements.+ */++button[disabled],+html input[disabled] {+ cursor: default;+}++/**+ * Remove inner padding and border in Firefox 4+.+ */++button::-moz-focus-inner,+input::-moz-focus-inner {+ border: 0;+ padding: 0;+}++/**+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in+ * the UA stylesheet.+ */++input {+ line-height: normal;+}++/**+ * It's recommended that you don't attempt to style these elements.+ * Firefox's implementation doesn't respect box-sizing, padding, or width.+ *+ * 1. Address box sizing set to `content-box` in IE 8/9/10.+ * 2. Remove excess padding in IE 8/9/10.+ */++input[type="checkbox"],+input[type="radio"] {+ box-sizing: border-box; /* 1 */+ padding: 0; /* 2 */+}++/**+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain+ * `font-size` values of the `input`, it causes the cursor style of the+ * decrement button to change from `default` to `text`.+ */++input[type="number"]::-webkit-inner-spin-button,+input[type="number"]::-webkit-outer-spin-button {+ height: auto;+}++/**+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome+ * (include `-moz` to future-proof).+ */++input[type="search"] {+ -webkit-appearance: textfield; /* 1 */+ -moz-box-sizing: content-box;+ -webkit-box-sizing: content-box; /* 2 */+ box-sizing: content-box;+}++/**+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.+ * Safari (but not Chrome) clips the cancel button when the search input has+ * padding (and `textfield` appearance).+ */++input[type="search"]::-webkit-search-cancel-button,+input[type="search"]::-webkit-search-decoration {+ -webkit-appearance: none;+}++/**+ * Define consistent border, margin, and padding.+ */++fieldset {+ border: 1px solid #c0c0c0;+ margin: 0 2px;+ padding: 0.35em 0.625em 0.75em;+}++/**+ * 1. Correct `color` not being inherited in IE 8/9/10/11.+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.+ */++legend {+ border: 0; /* 1 */+ padding: 0; /* 2 */+}++/**+ * Remove default vertical scrollbar in IE 8/9/10/11.+ */++textarea {+ overflow: auto;+}++/**+ * Don't inherit the `font-weight` (applied by a rule above).+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.+ */++optgroup {+ font-weight: bold;+}++/* Tables+ ========================================================================== */++/**+ * Remove most spacing between table cells.+ */++table {+ border-collapse: collapse;+ border-spacing: 0;+}++td,+th {+ padding: 0;+}
+ app/static/pursuit.css view
@@ -0,0 +1,703 @@+/** ************************************************************************* *+ ** Pursuit CSS+ **+ ** STRUCTURE+ **+ ** This CSS file is structured into several sections, from general to+ ** specific, and (mostly) alphabetically within the sections.+ **+ ** Several global element styles are used. This is not encouraged and should+ ** be kept to a minimum. If you want to add new styles you'll most likely+ ** want to add a new CSS component. See the Components section for examples.+ **+ ** CSS components use three simple naming ideas from the BEM system:+ ** - Block: `.my-component`+ ** - Element: `.my-component__item`+ ** - Modifier: `.my-component.my-component--highlighted`+ **+ ** Example:+ ** <div .my-component>+ ** <div .my-component__item>+ ** <div .my-component__item>+ ** ...+ ** <div .my-component.my-component--highlighted>+ ** <div .my-component__item>+ ** <div .my-component__item>+ **+ ** Components can be nested.+ **+ **+ ** TYPOGRAPHY+ **+ ** Typographic choices for sizes, line-heights and margins are based on a+ ** musical major third scale (4:5). This gives us a way to find numbers+ ** and relationships between them that are perceived as harmonic.+ **+ ** To make use of this modular scale, use a ratio of the form+ ** (5/4)^n+ ** where n ∈ ℤ, -6 ≤ n ≤ 8.+ ** ************************************************************************* */+/* Section: Variables+ * ========================================================================== */+/* Section: Document Styles+ * ========================================================================== */+html {+ box-sizing: border-box;+ /* This overflow rule prevents everything from shifting slightly to the side+ when moving from a page which isn't large enough to generate a scrollbar+ to one that is. */+ overflow-y: scroll;+}+*,+*::before,+*::after {+ box-sizing: inherit;+}+body {+ background-color: #ffffff;+ color: #000;+ font-family: "Roboto", sans-serif;+ font-size: 87.5%;+ line-height: 1.563;+}+@media (min-width: 38em) {+ body {+ font-size: 100%;+ }+}+/* Section: Utility Classes+ * ========================================================================== */+.clear-floats {+ clear: both;+}+.clearfix::before,+.clearfix::after {+ content: " ";+ display: table;+}+.clearfix::after {+ clear: both;+}+/* Content hidden like this will still be read by a screen reader */+.hide-visually {+ position: absolute;+ left: -10000px;+ top: auto;+ width: 1px;+ height: 1px;+ overflow: hidden;+}+/* Section: Layout+ * ========================================================================== */+.container {+ display: block;+ max-width: 66em;+ margin-left: auto;+ margin-right: auto;+ padding-left: 20px;+ padding-right: 20px;+}+.col {+ display: block;+ position: relative;+ width: 100%;+}+.col.col--main {+ margin-bottom: 3.08em;+}+.col.col--aside {+ margin-bottom: 2.44em;+}+@media (min-width: 52em) {+ .container {+ padding-left: 30px;+ padding-right: 30px;+ }+ .col.col--main {+ float: left;+ width: 63.655%;+ /* 66.6…% - 30px */+ }+ .col.col--aside {+ float: right;+ font-size: 87.5%;+ width: 33.333333%;+ }+}+@media (min-width: 66em) {+ .col.col--aside {+ font-size: inherit;+ }+}+/* Footer+ * Based on http://www.lwis.net/journal/2008/02/08/pure-css-sticky-footer/+ * Except we don't support IE6+ * -------------------------------------------------------------------------- */+html,+body {+ height: 100%;+}+.everything-except-footer {+ min-height: 100%;+ padding-bottom: 3em;+}+.footer {+ position: relative;+ height: 3em;+ margin-top: -3em;+ width: 100%;+ text-align: center;+ background-color: #1d222d;+ color: #f0f0f0;+}+.footer * {+ margin-bottom: 0;+}+/* Section: Element Styles+ *+ * Have as few of these as possible and keep them general, because they will+ * influence every component hereafter.+ * ========================================================================== */+:target {+ background-color: #f1f5f9;+}+a,+a:visited {+ color: #c4953a;+ text-decoration: none;+ font-weight: bold;+}+a:hover {+ color: #7b5904;+ text-decoration: none;+}+code,+pre {+ background-color: #f1f5f9;+ border-radius: 3px;+ color: #194a5b;+ font-family: "Roboto Mono", monospace;+ font-size: 87.5%;+}+:target code,+:target pre {+ background-color: #dfe8f1;+}+code {+ padding: 0.2em 0;+ margin: 0;+ white-space: pre-wrap;+ word-wrap: break-word;+}+code::before,+code::after {+ letter-spacing: -0.2em;+ content: "\00a0";+}+a > code {+ font-weight: normal;+}+a > code::before {+ content: "🡒";+ letter-spacing: 0.33em;+}+a:hover > code {+ color: #c4953a;+}+pre {+ margin-top: 0;+ margin-bottom: 0;+ padding: 1em 1.25rem;+ /* Using rem here to align with lists etc. */+ overflow: auto;+ white-space: pre;+ word-wrap: normal;+}+pre code {+ background-color: transparent;+ border: 0;+ font-size: 100%;+ max-width: auto;+ padding: 0;+ margin: 0;+ overflow: visible;+ line-height: inherit;+ white-space: pre;+ word-break: normal;+ word-wrap: normal;+}+pre code::before,+pre code::after {+ content: normal;+}+h1 {+ font-size: 3.052em;+ font-weight: 300;+ letter-spacing: -0.5px;+ line-height: 1.125;+ margin-top: 1.563rem;+ margin-bottom: 1.25rem;+}+@media (min-width: 52em) {+ h1 {+ font-size: 3.814em;+ margin-top: 5.96rem;+ }+}+h2 {+ font-size: 1.953em;+ font-weight: normal;+ line-height: 1.250;+ margin-top: 3.052rem;+ margin-bottom: 1rem;+}+h3 {+ font-size: 1.563em;+ font-weight: normal;+ line-height: 1.250;+ margin-top: 2.441rem;+ margin-bottom: 1rem;+}+h4 {+ font-size: 1.25em;+ font-weight: normal;+ margin-top: 2.441rem;+ margin-bottom: 1rem;+}+h1 + h2,+h1 + h3,+h1 + h4,+h2 + h3,+h2 + h4,+h3 + h4 {+ margin-top: 1rem;+}+hr {+ border: none;+ height: 1px;+ background-color: #cccccc;+}+img {+ border-style: none;+ max-width: 100%;+}+p {+ font-size: 1em;+ margin-top: 1rem;+ margin-bottom: 1rem;+}+table {+ border-bottom: 1px solid #cccccc;+ border-collapse: collapse;+ border-spacing: 0;+ margin-top: 1rem;+ margin-bottom: 1rem;+ width: 100%;+}+td,+th {+ text-align: left;+ padding: 0.41em 0.51em;+}+td {+ border-top: 1px solid #cccccc;+}+td:first-child,+th:first-child {+ padding-left: 0;+}+td:last-child,+th:last-child {+ padding-right: 0;+}+ul {+ list-style-type: none;+ margin-top: 1rem;+ margin-bottom: 1rem;+ padding-left: 0;+}+ul li {+ position: relative;+ padding-left: 1.250em;+}+ul li::before {+ position: absolute;+ color: #a0a0a0;+ content: "–";+ display: inline-block;+ margin-left: -1.25em;+ width: 1.250em;+}+/* Tying this tightly to ul at the moment because it's a slight variation thereof */+ul.ul--search li::before {+ content: "⚲";+ top: -0.2em;+ transform: rotate(-45deg);+}+ol {+ margin-top: 1rem;+ margin-bottom: 1rem;+ padding-left: 1.250em;+}+ol li {+ position: relative;+ padding-left: 0;+}+/* Section: Components+ * ========================================================================== */+/* Component: Badge+ * -------------------------------------------------------------------------- */+.badge {+ position: relative;+ top: -0.1em;+ display: inline-block;+ background-color: #000;+ border-radius: 1.3em;+ color: #fff;+ font-size: 77%;+ font-weight: bold;+ line-height: 1.563;+ text-align: center;+ height: 1.5em;+ width: 1.5em;+}+.badge.badge--package {+ background-color: #c4953a;+ letter-spacing: -0.1em;+}+.badge.badge--module {+ background-color: #75B134;+}+/* Component: Declarations+ * -------------------------------------------------------------------------- */+.decl__title {+ position: relative;+ padding-bottom: 0.328em;+ margin-bottom: 0.262em;+}+.decl__source {+ display: block;+ float: right;+ font-size: 64%;+ position: relative;+ top: 0.57em;+}+.decl__anchor,+.decl__anchor:visited {+ position: absolute;+ left: -0.8em;+ color: #bababa;+}+.decl__anchor:hover {+ color: #c4953a;+}+.decl__signature {+ background-color: transparent;+ border-radius: 0;+ border-top: 1px solid #cccccc;+ border-bottom: 1px solid #cccccc;+ padding: 0.328em 0;+}+.decl__signature code {+ display: block;+ padding-left: 2.441em;+ text-indent: -2.441em;+ white-space: normal;+}+:target .decl__signature,+:target .decl__signature code {+ /* We want the background to be transparent, even when the parent is a target */+ background-color: transparent;+}+.decl__body .keyword,+.decl__body .syntax {+ color: #0B71B4;+}+/* Component: Dependency Link+ * -------------------------------------------------------------------------- */+.deplink {+ /* Currently no root styles, but keep the class as a namespace */+}+.deplink__link {+ display: inline-block;+ margin-right: 0.41em;+}+.deplink__version {+ color: #666666;+ display: inline-block;+ font-size: 0.8em;+ line-height: 1;+}+/* Component: Grouped List+ * -------------------------------------------------------------------------- */+.grouped-list {+ border-top: 1px solid #cccccc;+ margin: 0 0 2.44em 0;+}+.grouped-list__title {+ color: #666666;+ font-size: 0.8em;+ font-weight: 300;+ letter-spacing: 1px;+ margin: 0.8em 0 -0.1em 0;+ text-transform: uppercase;+}+.grouped-list__item {+ margin: 0;+}+/* Component: Message+ * -------------------------------------------------------------------------- */+.message {+ border: 5px solid;+ border-radius: 5px;+ padding: 1em !important;+}+.message.message--error {+ background-color: #fff0f0;+ border-color: #c85050;+}+.message.message--not-available {+ background-color: #f0f096;+ border-color: #e3e33d;+}+/* Component: Multi Col+ * Multiple columns side by side+ * -------------------------------------------------------------------------- */+.multi-col {+ margin-bottom: 2.44em;+}+.multi-col__col {+ display: block;+ padding-right: 1em;+ position: relative;+ width: 100%;+}+@media (min-width: 38em) and (max-width: 51.999999em) {+ .multi-col__col {+ float: left;+ width: 50%;+ }+ .multi-col__col:nth-child(2n+3) {+ clear: both;+ }+}+@media (min-width: 52em) {+ .multi-col__col {+ float: left;+ width: 33.333333%;+ }+ .multi-col__col:nth-child(3n+4) {+ clear: both;+ }+}+/* Component: Page Title+ * -------------------------------------------------------------------------- */+.page-title {+ margin: 4.77em 0 1.56em;+ padding-bottom: 1.25em;+ position: relative;+}+.page-title__title {+ margin: 0 0 0 -0.05em;+ /* Visually align on left edge */+}+.page-title__label {+ position: relative;+ color: #666666;+ font-size: 0.8rem;+ font-weight: 300;+ letter-spacing: 1px;+ margin-bottom: -0.8em;+ text-transform: uppercase;+ z-index: 1;+}+/* Component: Top Banner+ * -------------------------------------------------------------------------- */+.top-banner {+ background-color: #1d222d;+ color: #f0f0f0;+ font-weight: normal;+}+.top-banner__logo,+.top-banner__logo:visited {+ float: left;+ color: #f0f0f0;+ font-size: 2.44em;+ font-weight: 300;+ line-height: 90px;+ margin: 0;+}+.top-banner__logo:hover {+ color: #c4953a;+ text-decoration: none;+}+.top-banner__form {+ margin-bottom: 1.25em;+}+.top-banner__form input {+ border: 1px solid #1d222d;+ border-radius: 3px;+ color: #1d222d;+ font-weight: 300;+ line-height: 2;+ padding: 0.21em 0.512em;+ width: 100%;+}+.top-banner__actions {+ float: right;+ text-align: right;+}+.top-banner__actions__item {+ display: inline-block;+ line-height: 90px;+ margin: 0;+ padding-left: 1.25em;+}+.top-banner__actions__item:first-child {+ padding-left: 0;+}+.top-banner__actions__item a,+.top-banner__actions__item a:visited {+ color: #f0f0f0;+}+.top-banner__actions__item a:hover {+ color: #c4953a;+}+@media (min-width: 38em) {+ .top-banner__logo {+ float: left;+ width: 25%;+ }+ .top-banner__form {+ float: left;+ line-height: 90px;+ margin-bottom: 0;+ width: 50%;+ }+ .top-banner__actions {+ float: right;+ width: 25%;+ }+}+/* Component: Search Results+ * -------------------------------------------------------------------------- */+.result.result--empty {+ font-size: 1.25em;+}+.result__title {+ font-size: 1.25em;+ margin-bottom: 0.2rem;+}+.result__badge {+ margin-left: -0.1em;+}+.result__body > *:first-child {+ margin-top: 0!important;+}+.result__body > *:last-child {+ margin-bottom: 0!important;+}+.result__signature {+ background-color: transparent;+ border-radius: 0;+ border-top: 1px solid #cccccc;+ border-bottom: 1px solid #cccccc;+ padding: 0.328em 0;+}+.result__signature code {+ display: block;+ padding-left: 2.441em;+ text-indent: -2.441em;+ white-space: normal;+}+.result__actions {+ margin-top: 0.2rem;+}+.result__actions__item {+ font-size: 80%;+}+.result__actions__item + .result__actions__item {+ margin-left: 0.65em;+}+/* Component: Version Selector+ * -------------------------------------------------------------------------- */+.version-selector {+ margin-bottom: 0.8em;+}+@media (min-width: 38em) {+ .version-selector {+ position: absolute;+ top: 0.8em;+ right: 0;+ margin-bottom: 0;+ }+}+/* Section: FIXME+ * These styles should be cleaned up+ * ========================================================================== */+/* Help paragraphs */+.help {+ padding: 5px 0;+}+.help h3 {+ /* FIXME: target with class */+ margin-top: 16px;+}+/* Section: Markdown+ * Github rendered README+ * ========================================================================== */+.markdown-body {+ /*+ Useful for narrow screens, such as mobiles. Documentation often contains URLs+ which would otherwise force the page to become wider, and force creation of+ horizontal scrollbars. Yuck.+ */+ word-wrap: break-word;+}+.markdown-body > *:first-child {+ margin-top: 0 !important;+}+.markdown-body > *:last-child {+ margin-bottom: 0 !important;+}+.markdown-body a:not([href]) {+ color: inherit;+ text-decoration: none;+}+.markdown-body blockquote {+ margin: 0;+ padding: 0 1em;+ color: #777;+ border-left: 0.25em solid #ddd;+}+.markdown-body blockquote > :first-child {+ margin-top: 0;+}+.markdown-body blockquote > :last-child {+ margin-bottom: 0;+}+.markdown-body .anchor {+ /* We hide the anchor because the link doesn't point to a valid location */+ display: none;+}+.markdown-body .pl-k {+ /* Keyword */+ color: #a0a0a0;+}+.markdown-body .pl-c1,+.markdown-body .pl-en {+ /* Not really sure what this is */+ color: #39d;+}+.markdown-body .pl-s {+ /* String literals */+ color: #1a1;+}+.markdown-body .pl-cce {+ /* String literal escape sequences */+ color: #921;+}+.markdown-body .pl-smi {+ /* type variables? */+ color: #62b;+}
examples/docs/bower.json view
@@ -15,6 +15,7 @@ "output" ], "dependencies": {+ "purescript-prelude": "./bower_components/purescript-prelude" }, "license": "MIT" }
+ examples/docs/resolutions.json view
@@ -0,0 +1,21 @@+{+ "canonicalDir": ".",+ "pkgMeta": {+ "dependencies": {+ "purescript-prelude": "./bower_components/purescript-prelude"+ }+ },+ "dependencies": {+ "purescript-prelude": {+ "canonicalDir": "bower_components/purescript-prelude",+ "pkgMeta": {+ "_resolution": {+ "type": "version",+ "tag": "v2.4.0",+ "commit": "21067a4c782f42d08bc877214f85b92ce6769b21"+ }+ },+ "dependencies": {}+ }+ }+}
examples/docs/src/ConstrainedArgument.purs view
@@ -4,6 +4,5 @@ type WithoutArgs = forall a. (Partial => a) -> a type WithArgs = forall a. (Foo a => a) -> a-type MultiWithoutArgs = forall a. ((Partial, Partial) => a) -> a-type MultiWithArgs = forall a b. ((Foo a, Foo b) => a) -> a-+type MultiWithoutArgs = forall a. (Partial => Partial => a) -> a+type MultiWithArgs = forall a b. (Foo a => Foo b => a) -> a
examples/docs/src/TypeClassWithFunDeps.purs view
@@ -2,4 +2,4 @@ module TypeClassWithFunDeps where class TypeClassWithFunDeps a b c d e | a b -> c, c -> d e where- aMember :: a+ aMember :: a -> b
examples/failing/1071.purs view
@@ -4,5 +4,5 @@ class Foo a b where foo :: a -> b -bar :: forall a. (Foo a) => a -> a+bar :: forall a. Foo a => a -> a bar a = a
examples/failing/1310.purs view
@@ -12,7 +12,7 @@ instance inject :: Inject f f where inj x = x -foreign import data Oops :: !+foreign import data Oops :: Effect main :: forall eff. Eff (oops :: Oops | eff) Unit main = inj (log "Oops")
− examples/failing/2445.purs
@@ -1,6 +0,0 @@--- @shouldFailWith ErrorParsingModule-module Main where--data X a = X--eg = \(X :: (forall a. X a)) -> X
+ examples/failing/2567.purs view
@@ -0,0 +1,5 @@+-- @shouldFailWith NoInstanceFound+module Main where++foo :: Int+foo = (0 :: Fail "This constraint should be checked" => Int)
examples/failing/2601.purs view
@@ -1,7 +1,7 @@ -- @shouldFailWith KindsDoNotUnify module Main where -type Syn (a :: * -> *) = String+type Syn (a :: Type -> Type) = String val :: Syn Int val = "bad"
+ examples/failing/2616.purs view
@@ -0,0 +1,9 @@+-- @shouldFailWith NoInstanceFound+module Main where+ +import Prelude++newtype Foo r = Foo { | r }++derive instance eqFoo :: Eq (Foo r)+derive instance ordFoo :: Ord (Foo r)
+ examples/failing/DuplicateProperties.purs view
@@ -0,0 +1,12 @@+-- @shouldFailWith TypesDoNotUnify+module DuplicateProperties where++import Prelude++foreign import data Test :: # Type -> Type++foreign import subtractX :: forall r. Test (x :: Unit | r) -> Test r++foreign import hasX :: Test (x :: Unit, y :: Unit)++baz = subtractX (subtractX hasX)
− examples/failing/DuplicateProperties1.purs
@@ -1,12 +0,0 @@--- @shouldFailWith TypesDoNotUnify-module DuplicateProperties where--import Prelude--foreign import data Test :: # * -> *--foreign import subtractX :: forall r. Test (x :: Unit | r) -> Test r--foreign import hasX :: Test (x :: Unit, y :: Unit)--baz = subtractX (subtractX hasX)
− examples/failing/DuplicateProperties2.purs
@@ -1,12 +0,0 @@--- @shouldFailWith DuplicateLabel-module DuplicateProperties where--import Prelude--foreign import data Test :: # * -> *--foreign import subtractX :: forall r. Test (x :: Unit | r) -> Test r--foreign import hasX :: forall r. Test (x :: Unit, y :: Unit | r)--baz = subtractX (subtractX hasX)
+ examples/failing/InvalidDerivedInstance.purs view
@@ -0,0 +1,8 @@+-- @shouldFailWith InvalidDerivedInstance+module Main where++import Prelude++data X = X++derive instance eqX :: Eq X X
+ examples/failing/InvalidDerivedInstance2.purs view
@@ -0,0 +1,6 @@+-- @shouldFailWith ExpectedTypeConstructor+module Main where++import Prelude++derive instance eqRecord :: Eq {}
+ examples/failing/LetPatterns1.purs view
@@ -0,0 +1,10 @@+-- @shouldFailWith ErrorParsingModule+module Main where++import Prelude++-- wrong binders for function, the first one should be VarBinder+x =+ let (X a b) x y = hoge+ in+ a
+ examples/failing/LetPatterns2.purs view
@@ -0,0 +1,14 @@+-- @shouldFailWith UnknownName+module Main where++import Prelude++data X a = X a++-- wrong dependency order+x =+ let+ b = a+ X a = X 10+ in+ b
+ examples/failing/LetPatterns3.purs view
@@ -0,0 +1,13 @@+-- @shouldFailWith IncorrectConstructorArity+module Main where++import Prelude++data X a = X a++-- a parameter binder should be with nullary constructor, or with parens+x =+ let+ a X b = b+ in+ a $ X 10
+ examples/failing/LetPatterns4.purs view
@@ -0,0 +1,6 @@+-- @shouldFailWith ErrorParsingModule+module Main where++data X a = X a++X a = a
+ examples/failing/NonExhaustivePatGuard.purs view
@@ -0,0 +1,5 @@+-- @shouldFailWith NoInstanceFound+module Main where++f :: Int -> Int+f x | 1 <- x = x
examples/failing/Superclasses5.purs view
@@ -8,19 +8,19 @@ class Su a where su :: a -> a -class (Su (Array a)) <= Cl a where+class Su (Array a) <= Cl a where cl :: a -> a -> a instance suNumber :: Su Number where su n = n + 1.0 -instance suArray :: (Su a) => Su (Array a) where+instance suArray :: Su a => Su (Array a) where su [x] = [su x] instance clNumber :: Cl Number where cl n m = n + m -test :: forall a. (Cl a) => a -> Array a+test :: forall a. Cl a => a -> Array a test x = su [cl x x] main = logShow $ test 10.0
+ examples/failing/UnusableTypeClassMethod.purs view
@@ -0,0 +1,7 @@+-- @shouldFailWith UnusableDeclaration+module Main where++class C a b where+ -- type doesn't contain `a`, which is also required to determine an instance+ c :: b+
+ examples/failing/UnusableTypeClassMethodConflictingIdent.purs view
@@ -0,0 +1,7 @@+-- @shouldFailWith UnusableDeclaration+module Main where++class C a where+ -- type doesn't contain the type class var `a`+ c :: forall a. a+
+ examples/failing/UnusableTypeClassMethodSynonym.purs view
@@ -0,0 +1,9 @@+-- @shouldFailWith UnusableDeclaration+module Main where++type M x = forall a. a++class C a where+ -- after synonym expansion, the type doesn't actually contain an `a`+ c :: M a+
+ examples/passing/1110.purs view
@@ -0,0 +1,26 @@+module Main where++import Prelude+import Control.Monad.Eff.Console (log)++data X a = X++x :: forall a. X a+x = X+ +type Y = { x :: X Int }++test :: forall m. Monad m => m Y+test = pure { x: x }++type Z t = forall x. t x -> (forall a. t a) -> t x++class C t where c :: Z t++instance cA :: C Array where+ c x _ = x++test2 :: forall m. Monad m => m { ccc :: Z Array }+test2 = pure { ccc: (c :: Z Array) }++main = log "Done"
examples/passing/1335.purs view
@@ -1,14 +1,14 @@-module Main where - -import Prelude -import Control.Monad.Eff.Console (log) - -x :: forall a. a -> String -x a = y "Test" - where - y :: forall a. (Show a) => a -> String - y a = show (a :: a) - -main = do - log (x 0) - log "Done" +module Main where++import Prelude+import Control.Monad.Eff.Console (log)++x :: forall a. a -> String+x a = y "Test"+ where+ y :: forall a. Show a => a -> String+ y a = show (a :: a)++main = do+ log (x 0)+ log "Done"
examples/passing/1697.purs view
@@ -6,17 +6,17 @@ _2 :: forall a. a -> a _2 a = a -x :: forall m. (Monad m) => m Unit+x :: forall m. Monad m => m Unit x = do _ <- pure unit pure unit -y :: forall m. (Monad m) => m Unit+y :: forall m. Monad m => m Unit y = do _ <- pure unit pure unit -wtf :: forall m. (Monad m) => m Unit+wtf :: forall m. Monad m => m Unit wtf = do _ <- pure unit let tmp = _2 1
examples/passing/1991.purs view
@@ -9,7 +9,7 @@ empty :: forall a. Array a empty = [] -foldMap :: forall a m. (Semigroup m) => (a -> m) -> Array a -> m+foldMap :: forall a m. Semigroup m => (a -> m) -> Array a -> m foldMap f [a, b, c, d, e] = f a <> f b <> f c <> f d <> f e foldMap f xs = foldMap f xs -- spin, not used
+ examples/passing/2609.purs view
@@ -0,0 +1,12 @@+module Main where++import Prelude+import Eg (Foo'(Bar'), (:->))+import Control.Monad.Eff (Eff)+import Control.Monad.Eff.Console (CONSOLE, log)++bar' :: Foo'+bar' = 4 :-> 5++main :: forall e. Eff (console :: CONSOLE | e) Unit+main = case bar' of Bar' l r -> log "Done"
+ examples/passing/2609/Eg.purs view
@@ -0,0 +1,6 @@+module Eg (Foo'(Bar'), (:->)) where++data Foo' = Bar' Int Int++infix 4 Bar' as :->+
+ examples/passing/2616.purs view
@@ -0,0 +1,13 @@+module Main where++import Prelude+import Control.Monad.Eff.Console (log)++newtype F r a = F { x :: a | r }++unF :: forall r a. F r a -> { x :: a | r }+unF (F x) = x++derive instance functorF :: Functor (F r)++main = log (unF (map id (F { x: "Done", y: 42 }))).x
+ examples/passing/2626.purs view
@@ -0,0 +1,13 @@+module Main where++import Control.Monad.Eff.Console (log)++f = \(x :: forall a. a -> a) -> x x++test1 = (f \x -> x) 1++g = \(x :: (forall a. a -> a) -> Int) -> x (\y -> y)++test2 = g \f -> if f true then f 0 else f 1++main = log "Done"
+ examples/passing/2663.purs view
@@ -0,0 +1,9 @@+module Main where++import Prelude+import Control.Monad.Eff.Console (log)++foo :: forall t. Warn "Example" => t -> t+foo x = x++main = when (foo 42 == 42) $ log "Done"
+ examples/passing/2689.purs view
@@ -0,0 +1,36 @@+module Main where++import Prelude+import Control.Monad.Eff.Console+import Data.Array.Partial+import Partial.Unsafe++sumTCObug = go id where + go f 0 = f + go f n =+ let+ f' a = n + a+ in+ go f' 0++sumTCObug' = go id where + go f 0 = f+ go f n = go (\a -> n + a) 0++count :: forall a. (a -> Boolean) -> Array a -> Int+count p = count' 0 where+ count' acc [] = acc+ count' acc xs =+ let h = unsafePartial head xs+ in count' (acc + if p h then 1 else 0) (unsafePartial tail xs)++main = do+ let x = sumTCObug 7 3+ y = sumTCObug' 7 3+ z = count (_ > 0) [-1, 0, 1]+ logShow x+ logShow y + logShow z+ if x == 10 && y == 10 && z == 1+ then log "Done"+ else log "Fail"
+ examples/passing/2695.purs view
@@ -0,0 +1,13 @@+module Main where++import Prelude+import Data.Generic+import Control.Monad.Eff.Console (log)++type Foo = { foo :: Int }++newtype Foo' = Foo' Foo++derive instance genericFoo :: Generic Foo'++main = log "Done"
+ examples/passing/2756.purs view
@@ -0,0 +1,20 @@+module Main where++import Control.Monad.Eff (Eff)+import Control.Monad.Eff.Console (log)+import Prelude++pu :: forall eff. Eff eff Unit+pu = pure unit++type C eff = { pu :: Eff eff Unit }++sampleC :: C ()+sampleC = { pu: pu }++newtype Identity a = Id a++sampleIdC :: Identity (C ())+sampleIdC = Id { pu : pu }++main = log "Done"
examples/passing/CheckTypeClass.purs view
@@ -9,8 +9,8 @@ class Foo a where foo :: Bar a -> Baz -foo_ :: forall a. (Foo a) => a -> Baz-foo_ x = foo ((mkBar :: forall a. (Foo a) => a -> Bar a) x)+foo_ :: forall a. Foo a => a -> Baz+foo_ x = foo ((mkBar :: forall a. Foo a => a -> Bar a) x) mkBar :: forall a. a -> Bar a mkBar _ = Bar
examples/passing/ClassRefSyntax.purs view
@@ -3,7 +3,7 @@ import Lib (class X, go) import Control.Monad.Eff.Console (log) -go' :: forall a. (X a) => a -> a+go' :: forall a. X a => a -> a go' = go main = log "Done"
examples/passing/Collatz.purs view
@@ -10,9 +10,9 @@ r <- newSTRef n count <- newSTRef 0 untilE $ do- modifySTRef count $ (+) 1+ _ <- modifySTRef count $ (+) 1 m <- readSTRef r- writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1+ _ <- writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1 pure $ m == 1 readSTRef count))
examples/passing/Console.purs view
@@ -4,10 +4,10 @@ import Control.Monad.Eff import Control.Monad.Eff.Console -replicateM_ :: forall m a. (Monad m) => Number -> m a -> m {}-replicateM_ 0.0 _ = pure {}+replicateM_ :: forall m a. Monad m => Number -> m a -> m Unit+replicateM_ 0.0 _ = pure unit replicateM_ n act = do- act+ _ <- act replicateM_ (n - 1.0) act main = do
+ examples/passing/ConstraintParens.purs view
@@ -0,0 +1,12 @@+module Main where++import Prelude+import Control.Monad.Eff.Console (log)++class Foo a where+ foo ∷ a → a++test ∷ ∀ a. (Foo a) ⇒ a → a+test = foo++main = log "Done"
examples/passing/DctorOperatorAlias.purs view
@@ -1,6 +1,6 @@ module Main where - import Prelude (Unit, bind, (==))+ import Prelude (Unit, bind, discard, (==)) import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) import Test.Assert (ASSERT, assert')
examples/passing/Do.purs view
@@ -31,8 +31,8 @@ Just (x + y) test3 = \_ -> do- Just 1.0- Nothing :: Maybe Number+ _ <- Just 1.0+ _ <- Nothing :: Maybe Number Just 2.0 test4 mx my = do
+ examples/passing/DuplicateProperties.purs view
@@ -0,0 +1,27 @@+module Main where++import Prelude+import Control.Monad.Eff.Console (log)++data RProxy (r :: # Type) = RProxy++data Proxy (a :: Type) = Proxy++subtractX :: forall r a. RProxy (x :: a | r) -> RProxy r+subtractX RProxy = RProxy++extractX :: forall r a. RProxy (x :: a | r) -> Proxy a+extractX RProxy = Proxy++hasX :: forall r a b. RProxy (x :: a, y :: b | r)+hasX = RProxy++test1 = subtractX (subtractX hasX)++test2+ :: forall r a b+ . RProxy (x :: a, x :: b, x :: Int | r)+ -> Proxy Int+test2 x = extractX (subtractX (subtractX x))++main = log "Done"
examples/passing/Eff.purs view
@@ -11,12 +11,12 @@ test2 = runPure (runST (do ref <- newSTRef 0.0- modifySTRef ref $ \n -> n + 1.0+ _ <- modifySTRef ref $ \n -> n + 1.0 readSTRef ref)) test3 = pureST (do ref <- newSTRef 0.0- modifySTRef ref $ \n -> n + 1.0+ _ <- modifySTRef ref $ \n -> n + 1.0 readSTRef ref) main = do
examples/passing/EntailsKindedType.purs view
@@ -4,8 +4,8 @@ import Control.Monad.Eff import Control.Monad.Eff.Console -test x = show (x :: _ :: *)+test x = show (x :: _ :: Type) main = do- when (show (unit :: Unit :: *) == "unit") (log "Done")+ when (show (unit :: Unit :: Type) == "unit") (log "Done") when (test unit == "unit") (log "Done")
examples/passing/ExtendedInfixOperators.purs view
@@ -4,7 +4,7 @@ import Control.Monad.Eff.Console (log, logShow) import Data.Function (on) -comparing :: forall a b. (Ord b) => (a -> b) -> a -> a -> Ordering+comparing :: forall a b. Ord b => (a -> b) -> a -> a -> Ordering comparing f = compare `on` f null [] = true
examples/passing/Fib.purs view
@@ -12,7 +12,7 @@ whileE ((>) 1000.0 <$> readSTRef n1) $ do n1' <- readSTRef n1 n2' <- readSTRef n2- writeSTRef n2 $ n1' + n2'- writeSTRef n1 n2'+ _ <- writeSTRef n2 $ n1' + n2'+ _ <- writeSTRef n1 n2' logShow n2' log "Done"
examples/passing/FinalTagless.purs view
@@ -7,7 +7,7 @@ num :: Number -> e Number add :: e Number -> e Number -> e Number -type Expr a = forall e. (E e) => e a+type Expr a = forall e. E e => e a data Id a = Id a
examples/passing/FunWithFunDeps.purs view
@@ -23,11 +23,11 @@ instance natMultS :: (NatMult m n r, NatPlus n r s) => NatMult (S m) n s -- Foreign Vect-foreign import data FVect :: * -> * -> *+foreign import data FVect :: Type -> Type -> Type foreign import fnil :: forall e. FVect Z e foreign import fcons :: forall n e. e -> FVect n e -> FVect (S n) e-foreign import fappend :: forall l r o e. (NatPlus l r o) => FVect l e -> FVect r e -> FVect o e-foreign import fflatten :: forall f s t o. (NatMult f s o) => FVect f (FVect s t) -> FVect o t+foreign import fappend :: forall l r o e. NatPlus l r o => FVect l e -> FVect r e -> FVect o e+foreign import fflatten :: forall f s t o. NatMult f s o => FVect f (FVect s t) -> FVect o t foreign import ftoArray :: forall n e. FVect n e -> Array e -- should be able to figure these out@@ -37,5 +37,5 @@ fexample3 = fsingleton fexample `fappend` fsingleton fexample `fappend` fsingleton fexample fexample4 = fflatten fexample3- + main = log "Done"
examples/passing/GenericsRep.purs view
@@ -43,6 +43,13 @@ instance eqV :: Eq V where eq x y = genericEq x y +newtype U = U {}++derive instance genericU :: Generic U _++instance eqU :: Eq U where+ eq x y = genericEq x y+ main :: Eff (console :: CONSOLE) Unit main = do logShow (X 0 == X 1)@@ -52,4 +59,5 @@ logShow (Y == Y :: Y Z) logShow (W { x: 0, y: "A" } == W { x: 0, y: "A" }) logShow (V { x: 0 } { x: 0 } == V { x: 0 } { x: 0 })+ logShow (U {} == U {}) log "Done"
examples/passing/Guards.purs view
@@ -12,11 +12,11 @@ z | y > 0.0 -> z / 2.0 z -> z * 3.0 + 1.0 -min :: forall a. (Ord a) => a -> a -> a+min :: forall a. Ord a => a -> a -> a min n m | n < m = n | otherwise = m -max :: forall a. (Ord a) => a -> a -> a+max :: forall a. Ord a => a -> a -> a max n m = case unit of _ | m < n -> n | otherwise -> m@@ -26,5 +26,39 @@ = x + y | otherwise = y - x++-- pattern guard example with two clauses+clunky1 :: Int -> Int -> Int+clunky1 a b | x <- max a b+ , x > 5+ = x+clunky1 a _ = a++clunky2 :: Int -> Int -> Int+clunky2 a b | x <- max a b+ , x > 5+ = x+ | otherwise+ = a + b++-- pattern guards on case epxressions+clunky_case1 :: Int -> Int -> Int+clunky_case1 a b =+ case unit of+ unit | x <- max a b+ , x > 5+ -> x+ | otherwise -> a + b++-- test indentation+clunky_case2 :: Int -> Int -> Int+clunky_case2 a b =+ case unit of+ unit+ | x <- max a b+ , x > 5+ -> x+ | otherwise+ -> a + b main = log $ min "Done" "ZZZZ"
examples/passing/KindedType.purs view
@@ -3,9 +3,9 @@ import Prelude import Control.Monad.Eff.Console (log) -type Star2Star f = f :: * -> *+type Star2Star f = f :: Type -> Type -type Star t = t :: *+type Star t = t :: Type test1 :: Star2Star Array String test1 = ["test"]@@ -15,17 +15,17 @@ test2 = f "test" -data Proxy (f :: * -> *) = Proxy+data Proxy (f :: Type -> Type) = Proxy test3 :: Proxy Array test3 = Proxy -type Test (f :: * -> *) = f String+type Test (f :: Type -> Type) = f String test4 :: Test Array test4 = ["test"] -class Clazz (a :: *) where+class Clazz (a :: Type) where def :: a instance clazzString :: Clazz String where
+ examples/passing/LetPattern.purs view
@@ -0,0 +1,196 @@+module Main where++import Prelude+import Partial.Unsafe (unsafePartial)+import Control.Monad.Eff (Eff)+import Control.Monad.Eff.Console (CONSOLE, log)+import Test.Assert (ASSERT, assert')++patternSimple :: Boolean+patternSimple =+ let x = 25252+ in+ x == 25252++patternDoSimple :: forall e. Eff e Boolean+patternDoSimple = do+ let x = 25252+ pure $ x == 25252++newtype X = X Int++patternNewtype :: Boolean+patternNewtype =+ let X a = X 123+ in+ a == 123++patternDoNewtype :: forall e. Eff e Boolean+patternDoNewtype = do+ let X a = X 123+ pure $ a == 123++data Y = Y Int String Boolean++patternData :: Boolean+patternData =+ let Y a b c = Y 456 "hello, world" false+ in+ a == 456 && b == "hello, world" && not c++patternDataIgnored :: Boolean+patternDataIgnored =+ let Y _ x _ = Y 789 "world, hello" true+ in+ x == "world, hello"++patternDoData :: forall e. Eff e Boolean+patternDoData = do+ let Y a b c = Y 456 "hello, world" false+ pure $ a == 456 && b == "hello, world" && not c++patternDoDataIgnored :: forall e. Eff e Boolean+patternDoDataIgnored = do+ let Y _ x _ = Y 789 "world, hello" true+ pure $ x == "world, hello"++patternArray :: Boolean+patternArray = unsafePartial $+ let [a, b] = [1, 2]+ in+ a == 1 && b == 2++patternDoArray :: forall e. Eff e Boolean+patternDoArray = unsafePartial do+ let [a, b] = [1, 2]+ pure $ a == 1 && b == 2++patternMultiple :: Boolean+patternMultiple = unsafePartial $+ let+ x = 25252+ X a = X x+ Y b c d = Y x "hello, world" false+ Y _ e _ = Y 789 "world, hello" true+ [f, g] = [1, 2]+ in+ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&+ not d && e == "world, hello" && f == 1 && g == 2++patternDoMultiple :: forall e. Eff e Boolean+patternDoMultiple = unsafePartial do+ let+ x = 25252+ X a = X x+ Y b c d = Y x "hello, world" false+ Y _ e _ = Y 789 "world, hello" true+ [f, g] = [1, 2]+ pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&+ not d && e == "world, hello" && f == 1 && g == 2++patternMultipleWithNormal :: Boolean+patternMultipleWithNormal = unsafePartial $+ let+ x = 25252+ X a = X x+ y = 2525+ Y b c d = Y y "hello, world" false+ in+ x == 25252 && y == 2525 &&+ a == 25252 && b == 2525 && c == "hello, world" && not d++patternDoMultipleWithNormal :: forall e. Eff e Boolean+patternDoMultipleWithNormal = unsafePartial do+ let+ x = 25252+ X a = X x+ y = 2525+ Y b c d = Y y "hello, world" false+ pure $ x == 25252 && y == 2525 &&+ a == 25252 && b == 2525 && c == "hello, world" && not d++patternWithParens :: Boolean+patternWithParens = unsafePartial $+ let+ (x) = 25252+ (X a) = X x+ (Y b c d) = Y x "hello, world" false+ (Y _ e _) = Y 789 "world, hello" true+ ([f, g]) = [1, 2]+ in+ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&+ not d && e == "world, hello" && f == 1 && g == 2++patternDoWithParens :: forall e. Eff e Boolean+patternDoWithParens = unsafePartial do+ let+ (x) = 25252+ (X a) = X x+ (Y b c d) = Y x "hello, world" false+ (Y _ e _) = Y 789 "world, hello" true+ ([f, g]) = [1, 2]+ pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&+ not d && e == "world, hello" && f == 1 && g == 2++patternWithNamedBinder :: Boolean+patternWithNamedBinder = unsafePartial $+ let+ a@{x, y} = {x: 10, y: 20}+ in+ a.x == 10 && x == 10 && a.y == 20 && y == 20++patternDoWithNamedBinder :: forall e. Eff e Boolean+patternDoWithNamedBinder = unsafePartial do+ let+ a@{x, y} = {x: 10, y: 20}+ pure $+ a.x == 10 && x == 10 && a.y == 20 && y == 20++data List a = Nil | Cons a (List a)+infixr 6 Cons as :++instance eqList :: Eq a => Eq (List a) where+ eq xs ys = go xs ys true+ where+ go _ _ false = false+ go Nil Nil acc = acc+ go (x : xs') (y : ys') acc = go xs' ys' $ acc && (y == x)+ go _ _ _ = false++patternWithInfixOp :: Boolean+patternWithInfixOp = unsafePartial $+ let+ x : xs = 1 : 2 : 3 : 4 : Nil+ in+ x == 1 && xs == 2 : 3 : 4 : Nil++patternDoWithInfixOp :: forall e. Eff e Boolean+patternDoWithInfixOp = unsafePartial do+ let+ x : xs = 1 : 2 : 3 : 4 : Nil+ pure $+ x == 1 && xs == 2 : 3 : 4 : Nil++main :: Eff (assert :: ASSERT, console :: CONSOLE) Unit+main = do+ assert' "simple variable pattern" patternSimple+ assert' "simple variable pattern with do" =<< patternDoSimple+ assert' "constructor pattern (newtype)" patternNewtype+ assert' "constructor pattern (newtype) with do" =<< patternDoNewtype+ assert' "constructor pattern (data)" patternData+ assert' "constructor pattern with ignorances" patternDataIgnored+ assert' "constructor pattern (data) with do" =<< patternDoData+ assert' "constructor pattern with ignorances and do" =<< patternDoDataIgnored+ assert' "array pattern" patternArray+ assert' "array pattern with do" =<< patternDoArray+ assert' "multiple patterns" patternMultiple+ assert' "multiple patterns with do" =<< patternDoMultiple+ assert' "multiple patterns with normal let's" patternMultipleWithNormal+ assert' "multiple patterns with normal let's and do" =<< patternDoMultipleWithNormal+ assert' "multiple patterns with parens" patternWithParens+ assert' "multiple patterns with parens and do" =<< patternDoWithParens+ assert' "multiple patterns with named binder" patternWithNamedBinder+ assert' "multiple patterns with named binder and do" =<< patternDoWithNamedBinder+ assert' "pattern with infix operator" patternWithInfixOp+ assert' "pattern with infix operator and do" =<< patternDoWithInfixOp+ log "Done"
examples/passing/MutRec2.purs view
@@ -7,7 +7,7 @@ data B = B A -foreign import data S :: *+foreign import data S :: Type f :: A -> S f a = case a of A b -> g b
examples/passing/MutRec3.purs view
@@ -7,7 +7,7 @@ data B = B A -foreign import data S :: *+foreign import data S :: Type f a = case a of A b -> g b
examples/passing/NakedConstraint.purs view
@@ -4,7 +4,7 @@ data List a = Nil | Cons a (List a) -head :: (Partial) => List Int -> Int+head :: Partial => List Int -> Int head (Cons x _) = x main = log "Done"
examples/passing/NewtypeClass.purs view
@@ -24,7 +24,8 @@ ala :: forall f t a- . (Functor f, Newtype t a)+ . Functor f+ => Newtype t a => (a -> t) -> ((a -> t) -> f t) -> f a
examples/passing/Operators.purs view
@@ -11,7 +11,7 @@ infix 4 op1 as ?! -test1 :: forall n. (Semiring n) => n -> n -> (n -> n -> n) -> n+test1 :: forall n. Semiring n => n -> n -> (n -> n -> n) -> n test1 x y z = x * y + z x y test2 = (\x -> x.foo false) { foo : \_ -> 1.0 }
examples/passing/OverlappingInstances2.purs view
@@ -1,27 +1,27 @@-module Main where - -import Prelude -import Control.Monad.Eff.Console (log) -import Test.Assert (assert) - -data A = A | B - -instance eqA1 :: Eq A where - eq A A = true - eq B B = true - eq _ _ = false - -instance eqA2 :: Eq A where - eq _ _ = true - -instance ordA :: Ord A where - compare A B = LT - compare B A = GT - compare _ _ = EQ - -test :: forall a. (Ord a) => a -> a -> String -test x y = show $ x == y - -main = do - assert $ test A B == "false" - log "Done" +module Main where++import Prelude+import Control.Monad.Eff.Console (log)+import Test.Assert (assert)++data A = A | B++instance eqA1 :: Eq A where+ eq A A = true+ eq B B = true+ eq _ _ = false++instance eqA2 :: Eq A where+ eq _ _ = true++instance ordA :: Ord A where+ compare A B = LT+ compare B A = GT+ compare _ _ = EQ++test :: forall a. Ord a => a -> a -> String+test x y = show $ x == y++main = do+ assert $ test A B == "false"+ log "Done"
examples/passing/OverlappingInstances3.purs view
@@ -1,20 +1,20 @@-module Main where - -import Prelude -import Control.Monad.Eff.Console (log) -import Test.Assert (assert) - -class Foo a - -instance foo1 :: Foo Number - -instance foo2 :: Foo Number - -test :: forall a. (Foo a) => a -> a -test a = a - -test1 = test 0.0 - -main = do - assert (test1 == 0.0) - log "Done" +module Main where++import Prelude+import Control.Monad.Eff.Console (log)+import Test.Assert (assert)++class Foo a++instance foo1 :: Foo Number++instance foo2 :: Foo Number++test :: forall a. Foo a => a -> a+test a = a++test1 = test 0.0++main = do+ assert (test1 == 0.0)+ log "Done"
examples/passing/PrimedTypeName.purs view
@@ -1,20 +1,20 @@-module Main (T, T', T'', T''', main) where - -import Prelude -import Control.Monad.Eff.Console (log) - -data T a = T -type T' = T Unit - -data T'' = TP - -foreign import data T''' ∷ * - -instance eqT ∷ Eq T'' where - eq _ _ = true - -type A' a b = b → a - -infixr 4 type A' as ↫ - -main = log "Done" +module Main (T, T', T'', T''', main) where++import Prelude+import Control.Monad.Eff.Console (log)++data T a = T+type T' = T Unit++data T'' = TP++foreign import data T''' ∷ Type++instance eqT ∷ Eq T'' where+ eq _ _ = true++type A' a b = b → a++infixr 4 type A' as ↫++main = log "Done"
examples/passing/Rank2TypeSynonym.purs view
@@ -3,7 +3,7 @@ import Prelude import Control.Monad.Eff.Console (log, logShow) -type Foo a = forall f. (Monad f) => f a+type Foo a = forall f. Monad f => f a foo :: forall a. a -> Foo a foo x = pure x
examples/passing/RebindableSyntax.purs view
@@ -1,43 +1,43 @@-module Main where - -import Prelude -import Control.Monad.Eff.Console (log) - -example1 :: String -example1 = do - "Do" - " notation" - " for" - " Semigroup" - where - bind x f = x <> f unit - -applySecond :: forall f a b. (Apply f) => f a -> f b -> f b -applySecond fa fb = const id <$> fa <*> fb - -infixl 4 applySecond as *> - -newtype Const a b = Const a - -runConst :: forall a b. Const a b -> a -runConst (Const a) = a - -instance functorConst :: Functor (Const a) where - map _ (Const a) = Const a - -instance applyConst :: (Semigroup a) => Apply (Const a) where - apply (Const a1) (Const a2) = Const (a1 <> a2) - -example2 :: Const String Unit -example2 = do - Const "Do" - Const " notation" - Const " for" - Const " Apply" - where - bind x f = x *> f unit - -main = do - log example1 - log $ runConst example2 - log "Done" +module Main where++import Prelude+import Control.Monad.Eff.Console (log)++example1 :: String+example1 = do+ "Do"+ " notation"+ " for"+ " Semigroup"+ where+ discard x f = x <> f unit++applySecond :: forall f a b. Apply f => f a -> f b -> f b+applySecond fa fb = const id <$> fa <*> fb++infixl 4 applySecond as *>++newtype Const a b = Const a++runConst :: forall a b. Const a b -> a+runConst (Const a) = a++instance functorConst :: Functor (Const a) where+ map _ (Const a) = Const a++instance applyConst :: Semigroup a => Apply (Const a) where+ apply (Const a1) (Const a2) = Const (a1 <> a2)++example2 :: Const String Unit+example2 = do+ Const "Do"+ Const " notation"+ Const " for"+ Const " Apply"+ where+ discard x f = x *> f unit++main = do+ log example1+ log $ runConst example2+ log "Done"
examples/passing/RowPolyInstanceContext.purs view
@@ -14,7 +14,7 @@ test1 :: forall r . S { foo :: String | r } Unit test1 = state $ \o -> o { foo = o.foo <> "!" } -test2 :: forall m r . (T { foo :: String | r } m) => m Unit+test2 :: forall m r . T { foo :: String | r } m => m Unit test2 = state $ \o -> o { foo = o.foo <> "!" } main = do
+ examples/passing/RowUnion.js view
@@ -0,0 +1,10 @@+"use strict";++exports.merge = function (dict) {+ return function (l) {+ return function (r) {+ var o = {};+ return Object.assign(o, r, l);+ };+ };+};
+ examples/passing/RowUnion.purs view
@@ -0,0 +1,68 @@+module Main where++import Prelude+import Control.Monad.Eff+import Control.Monad.Eff.Console++foreign import merge+ :: forall r1 r2 r3+ . Union r1 r2 r3+ => Record r1+ -> Record r2+ -> Record r3++test1 = merge { x: 1 } { y: true }++test2 = merge { x: 1 } { x: true }++mergeWithExtras+ :: forall r1 r2 r3+ . Union r1 (y :: Boolean | r2) (y :: Boolean | r3)+ => { x :: Int | r1 }+ -> { y :: Boolean | r2 }+ -> { x :: Int, y :: Boolean | r3}+mergeWithExtras = merge++test3 x = merge { x: 1 } x+test3' x = merge x { x: 1 }++type Mandatory r = (x :: Int | r)+type Optional r = (x :: Int, y :: Int, z :: Int | r)++withDefaults+ :: forall r s+ . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)+ => Record (Mandatory r)+ -> Record (Optional s)+withDefaults p = merge p { y: 1, z: 1 }++withDefaultsClosed+ :: forall r s+ . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)+ => Subrow s (y :: Int, z :: Int)+ => Record (Mandatory r)+ -> Record (Optional s)+withDefaultsClosed p = merge p { y: 1, z: 1 }++test4 = withDefaults { x: 1, y: 2 }++-- r is a subrow of s if Union r t s for some t.+class Subrow (r :: # Type) (s :: # Type)+instance subrow :: Union r t s => Subrow r s++main :: Eff (console :: CONSOLE) Unit+main = do+ logShow test1.x+ logShow test1.y+ logShow (test1.x == 1)+ logShow (mergeWithExtras { x: 1 } { x: 0, y: true, z: 42.0 }).x+ logShow (withDefaults { x: 1 }).x+ logShow (withDefaults { x: 1 }).y+ logShow (withDefaults { x: 1 }).z+ logShow (withDefaults { x: 1, y: 2 }).x+ logShow (withDefaults { x: 1, y: 2 }).y+ logShow (withDefaults { x: 1, y: 2 }).z+ logShow (withDefaultsClosed { x: 1, y: 2 }).x+ logShow (withDefaultsClosed { x: 1, y: 2 }).y+ logShow (withDefaultsClosed { x: 1, y: 2 }).z+ log "Done"
examples/passing/Sequence.purs view
@@ -7,7 +7,7 @@ data List a = Cons a (List a) | Nil class Sequence t where- sequence :: forall m a. (Monad m) => t (m a) -> m (t a)+ sequence :: forall m a. Monad m => t (m a) -> m (t a) instance sequenceList :: Sequence List where sequence Nil = pure Nil
examples/passing/SequenceDesugared.purs view
@@ -6,12 +6,12 @@ data List a = Cons a (List a) | Nil -data Sequence t = Sequence (forall m a. (Monad m) => t (m a) -> m (t a))+data Sequence t = Sequence (forall m a. Monad m => t (m a) -> m (t a)) -sequence :: forall t. Sequence t -> (forall m a. (Monad m) => t (m a) -> m (t a))+sequence :: forall t. Sequence t -> (forall m a. Monad m => t (m a) -> m (t a)) sequence (Sequence s) = s -sequenceListSeq :: forall m a. (Monad m) => List (m a) -> m (List a)+sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a) sequenceListSeq Nil = pure Nil sequenceListSeq (Cons x xs) = Cons <$> x <*> sequenceListSeq xs @@ -24,15 +24,15 @@ Cons x xs -> Cons <$> x <*> sequence sequenceList' xs)) sequenceList'' :: Sequence List-sequenceList'' = Sequence (sequenceListSeq :: forall m a. (Monad m) => List (m a) -> m (List a))+sequenceList'' = Sequence (sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a)) sequenceList''' :: Sequence List sequenceList''' = Sequence ((\val -> case val of Nil -> pure Nil- Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. (Monad m) => List (m a) -> m (List a))+ Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. Monad m => List (m a) -> m (List a)) main = do- sequence sequenceList $ Cons (log "Done") Nil- sequence sequenceList' $ Cons (log "Done") Nil- sequence sequenceList'' $ Cons (log "Done") Nil- sequence sequenceList''' $ Cons (log "Done") Nil+ void $ sequence sequenceList $ Cons (log "Done") Nil+ void $ sequence sequenceList' $ Cons (log "Done") Nil+ void $ sequence sequenceList'' $ Cons (log "Done") Nil+ void $ sequence sequenceList''' $ Cons (log "Done") Nil
examples/passing/StringEscapes.purs view
@@ -1,26 +1,26 @@-module Main where - -import Prelude ((==), (/=), (<>), bind) -import Test.Assert (assert, assert') -import Control.Monad.Eff.Console (log) - -singleCharacter = "\0\b\t\n\v\f\r\"\\" == "\x0\x8\x9\xA\xB\xC\xD\x22\x5C" -hex = "\x1D306\x2603\x3C6\xE0\x0" == "𝌆☃φà\0" -decimal = "\119558\9731\966\224\0" == "𝌆☃φà\0" -surrogatePair = "\xD834\xDF06" == "\x1D306" -highSurrogate = "\xD834" -lowSurrogate = "\xDF06" -loneSurrogates = (highSurrogate <> lowSurrogate) == "\x1D306" -outOfOrderSurrogates = (lowSurrogate <> highSurrogate) == "\xDF06\xD834" -replacement = "\xFFFD" -notReplacing = replacement /= highSurrogate - -main = do - assert' "single-character escape sequences" singleCharacter - assert' "hex escape sequences" hex - assert' "decimal escape sequences" decimal - assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair - assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates - assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates - assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing - log "Done" +module Main where++import Prelude ((==), (/=), (<>), discard)+import Test.Assert (assert, assert')+import Control.Monad.Eff.Console (log)++singleCharacter = "\0\b\t\n\v\f\r\"\\" == "\x0\x8\x9\xA\xB\xC\xD\x22\x5C"+hex = "\x1D306\x2603\x3C6\xE0\x0" == "𝌆☃φà\0"+decimal = "\119558\9731\966\224\0" == "𝌆☃φà\0"+surrogatePair = "\xD834\xDF06" == "\x1D306"+highSurrogate = "\xD834"+lowSurrogate = "\xDF06"+loneSurrogates = (highSurrogate <> lowSurrogate) == "\x1D306"+outOfOrderSurrogates = (lowSurrogate <> highSurrogate) == "\xDF06\xD834"+replacement = "\xFFFD"+notReplacing = replacement /= highSurrogate++main = do+ assert' "single-character escape sequences" singleCharacter+ assert' "hex escape sequences" hex+ assert' "decimal escape sequences" decimal+ assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair+ assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates+ assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates+ assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing+ log "Done"
examples/passing/Superclasses1.purs view
@@ -15,7 +15,7 @@ instance clNumber :: Cl Number where cl n m = n + m -test :: forall a. (Cl a) => a -> a+test :: forall a. Cl a => a -> a test a = su (cl a a) main = do
examples/passing/Superclasses3.purs view
@@ -4,13 +4,13 @@ import Control.Monad.Eff.Console import Control.Monad.Eff -class (Monad m) <= MonadWriter w m where+class Monad m <= MonadWriter w m where tell :: w -> m Unit -testFunctor :: forall m. (Monad m) => m Number -> m Number+testFunctor :: forall m. Monad m => m Number -> m Number testFunctor n = (+) 1.0 <$> n -test :: forall w m. (Monad m, MonadWriter w m) => w -> m Unit+test :: forall w m. Monad m => MonadWriter w m => w -> m Unit test w = do tell w tell w
examples/passing/TypeClasses.purs view
@@ -5,19 +5,19 @@ test1 = \_ -> show "testing" -f :: forall a. (Show a) => a -> String+f :: forall a. Show a => a -> String f x = show x test2 = \_ -> f "testing" -test7 :: forall a. (Show a) => a -> String+test7 :: forall a. Show a => a -> String test7 = show test8 = \_ -> show $ "testing" data Data a = Data a -instance showData :: (Show a) => Show (Data a) where+instance showData :: Show a => Show (Data a) where show (Data a) = "Data (" <> show a <> ")" test3 = \_ -> show (Data "testing")@@ -53,7 +53,7 @@ instance monadMaybe :: Monad Maybe -test4 :: forall a m. (Monad m) => a -> m Number+test4 :: forall a m. Monad m => a -> m Number test4 = \_ -> pure 1.0 test5 = \_ -> Just 1.0 >>= \n -> pure (n + 1.0)
examples/passing/TypeWildcards.purs view
@@ -6,7 +6,7 @@ testTopLevel :: _ -> _ testTopLevel n = n + 1.0 -test :: forall a. (Eq a) => (a -> a) -> a -> a+test :: forall a. Eq a => (a -> a) -> a -> a test f a = go (f a) a where go :: _ -> _ -> _
examples/passing/TypedBinders.purs view
@@ -7,7 +7,7 @@ class MonadState s m where get :: m s- put :: s -> m {}+ put :: s -> m Unit data State s a = State (s -> Tuple s a) @@ -30,9 +30,9 @@ instance monadStateState :: MonadState s (State s) where get = State (\s -> Tuple s s)- put s = State (\_ -> Tuple s {})+ put s = State (\_ -> Tuple s unit) -modify :: forall m s. (Monad m, MonadState s m) => (s -> s) -> m {}+modify :: forall m s. Monad m => MonadState s m => (s -> s) -> m Unit modify f = do s <- get put (f s)
examples/passing/UnicodeType.purs view
@@ -4,10 +4,10 @@ import Control.Monad.Eff.Console (log) class Monad m ⇐ Monad1 m where- f1 :: Int+ f1 :: m Int class Monad m <= Monad2 m where- f2 :: Int+ f2 :: m Int f ∷ ∀ m. Monad m ⇒ Int → m Int f n = do
examples/passing/UnifyInTypeInstanceLookup.purs view
@@ -12,13 +12,13 @@ instance eqT :: EQ x x T instance eqF :: EQ x y F -test :: forall a b. (EQ a b T) => a -> b -> a+test :: forall a b. EQ a b T => a -> b -> a test a _ = a spin :: forall a b. a -> b spin a = spin a --- Expected type: +-- Expected type: -- forall t. (EQ t (S Z) T) => t test1 = test (spin 1) (S Z)
examples/passing/UnknownInTypeClassLookup.purs view
@@ -7,7 +7,7 @@ instance eqAA :: EQ a a -test :: forall a b. (EQ a b) => a -> b -> String+test :: forall a b. EQ a b => a -> b -> String test _ _ = "Done" runTest a = test a a
+ examples/passing/UsableTypeClassMethods.purs view
@@ -0,0 +1,35 @@+-- this is testing that we don't see an `UnusableDeclaration` error for type+-- class methods that should be valid based on various configurations of fundeps+module Main where++import Control.Monad.Eff.Console (log)++-- no fundeps+class C0 a b where+ c0 :: a -> b++-- simple fundep+class C1 a b | a -> b where+ c1 :: a+ c1' :: a -> b++-- transitive+class C2 a b c | a -> b, b -> c where+ c2 :: a+ c2' :: a -> b+ c2'' :: a -> c+ c2''' :: a -> b -> c++-- with cycles+class C3 a b c | a -> b, b -> a, b -> c where+ c3 :: a+ c3' :: b+ c3'' :: a -> c+ c3''' :: b -> c+ c3'''' :: a -> b -> c++-- nullary class+class C4 where+ c4 :: forall a. a++main = log "Done"
+ examples/warning/ShadowedBinderPatternGuard.purs view
@@ -0,0 +1,7 @@+-- @shouldWarnWith ShadowedName+module Main where++f :: Int -> Int+f n | i <- true -- this i is shadowed+ , i <- 1234+ = i
+ examples/warning/ShadowedNameParens.purs view
@@ -0,0 +1,5 @@+-- @shouldWarnWith ShadowedName+module Main where++f :: Int -> Int -> Int+f n = \(n) -> 1
− hierarchy/Main.hs
@@ -1,119 +0,0 @@------------------------------------------------------------------------------------ Module : Main--- Copyright : (c) Hardy Jones 2014--- License : MIT (http://opensource.org/licenses/MIT)------ Maintainer : Hardy Jones <jones3.hardy@gmail.com>--- Stability : experimental--- Portability :------ |--- Generate Directed Graphs of PureScript TypeClasses-----------------------------------------------------------------------------------{-# LANGUAGE TupleSections #-}-{-# LANGUAGE DataKinds #-}--module Main where--import Control.Applicative (optional)-import Control.Monad (unless)--import Data.List (intercalate,nub,sort)-import Data.Foldable (for_)-import Data.Version (showVersion)-import Data.Monoid ((<>))-import qualified Data.Text as T--import Options.Applicative (Parser)-import qualified Options.Applicative as Opts-import System.Directory (createDirectoryIfMissing)-import System.FilePath ((</>))-import System.FilePath.Glob (glob)-import System.Exit (exitFailure, exitSuccess)-import System.IO (hPutStr, stderr)-import System.IO.UTF8 (readUTF8FileT)--import qualified Language.PureScript as P-import qualified Paths_purescript as Paths--data HierarchyOptions = HierarchyOptions- { hierachyInput :: FilePath- , hierarchyOutput :: Maybe FilePath- }--newtype SuperMap = SuperMap { unSuperMap :: Either (P.ProperName 'P.ClassName) (P.ProperName 'P.ClassName, P.ProperName 'P.ClassName) }- deriving Eq--instance Show SuperMap where- show (SuperMap (Left sub)) = show sub- show (SuperMap (Right (super, sub))) = show super ++ " -> " ++ show sub--instance Ord SuperMap where- compare (SuperMap s) (SuperMap s') = getCls s `compare` getCls s'- where- getCls = either id snd--runModuleName :: P.ModuleName -> String-runModuleName (P.ModuleName pns) = intercalate "_" ((T.unpack . P.runProperName) `map` pns)--readInput :: [FilePath] -> IO (Either P.MultipleErrors [P.Module])-readInput paths = do- content <- mapM (\path -> (path, ) <$> readUTF8FileT path) paths- return $ map snd <$> P.parseModulesFromFiles id content--compile :: HierarchyOptions -> IO ()-compile (HierarchyOptions inputGlob mOutput) = do- input <- glob inputGlob- modules <- readInput input- case modules of- Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure- Right ms -> do- for_ ms $ \(P.Module _ _ moduleName decls _) ->- let name = runModuleName moduleName- tcs = filter P.isTypeClassDeclaration decls- supers = sort . nub . filter (not . null) $ fmap superClasses tcs- prologue = "digraph " ++ name ++ " {\n"- body = intercalate "\n" (concatMap (fmap (\s -> " " ++ show s ++ ";")) supers)- epilogue = "\n}"- hier = prologue ++ body ++ epilogue- in unless (null supers) $ case mOutput of- Just output -> do- createDirectoryIfMissing True output- writeFile (output </> name) hier- Nothing -> putStrLn hier- exitSuccess--superClasses :: P.Declaration -> [SuperMap]-superClasses (P.TypeClassDeclaration sub _ supers@(_:_) _ _) =- fmap (\(P.Constraint (P.Qualified _ super) _ _) -> SuperMap (Right (super, sub))) supers-superClasses (P.TypeClassDeclaration sub _ _ _ _) = [SuperMap (Left sub)]-superClasses (P.PositionedDeclaration _ _ decl) = superClasses decl-superClasses _ = []--inputFile :: Parser FilePath-inputFile = Opts.strArgument $- Opts.metavar "FILE"- <> Opts.value "main.purs"- <> Opts.showDefault- <> Opts.help "The input file to generate a hierarchy from"--outputFile :: Parser (Maybe FilePath)-outputFile = optional . Opts.strOption $- Opts.short 'o'- <> Opts.long "output"- <> Opts.help "The output directory"--pscOptions :: Parser HierarchyOptions-pscOptions = HierarchyOptions <$> inputFile- <*> outputFile--main :: IO ()-main = Opts.execParser opts >>= compile- where- opts = Opts.info (Opts.helper <*> pscOptions) infoModList- infoModList = Opts.fullDesc <> headerInfo <> footerInfo- headerInfo = Opts.header "hierarchy - Creates a GraphViz directed graph of PureScript TypeClasses"- footerInfo = Opts.footer $ "hierarchy " ++ showVersion Paths.version
− psc-bundle/Main.hs
@@ -1,147 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE RecordWildCards #-}---- | Bundles compiled PureScript modules for the browser.-module Main (main) where--import Data.Traversable (for)-import Data.Version (showVersion)-import Data.Monoid ((<>))-import Data.Aeson (encode)-import Data.Maybe (isNothing)--import Control.Applicative-import Control.Monad-import Control.Monad.Error.Class-import Control.Monad.Trans.Except-import Control.Monad.IO.Class--import System.FilePath (takeDirectory, (</>), (<.>), takeFileName)-import System.FilePath.Glob (glob)-import System.Exit (exitFailure)-import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)-import System.IO.UTF8 (readUTF8File, writeUTF8File)-import System.Directory (createDirectoryIfMissing, getCurrentDirectory)--import qualified Data.ByteString.Lazy as B-import qualified Data.ByteString.UTF8 as BU8--import Language.PureScript.Bundle--import Options.Applicative (Parser, ParseError (..))-import qualified Options.Applicative as Opts--import qualified Paths_purescript as Paths--import SourceMap-import SourceMap.Types---- | Command line options.-data Options = Options- { optionsInputFiles :: [FilePath]- , optionsOutputFile :: Maybe FilePath- , optionsEntryPoints :: [String]- , optionsMainModule :: Maybe String- , optionsNamespace :: String- , optionsSourceMaps :: Bool- } deriving Show---- | The main application function.--- This function parses the input files, performs dead code elimination, filters empty modules--- and generates and prints the final Javascript bundle.-app :: (MonadError ErrorMessage m, MonadIO m) => Options -> m (Maybe SourceMapping, String)-app Options{..} = do- inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles- when (null inputFiles) . liftIO $ do- hPutStrLn stderr "psc-bundle: No input files."- exitFailure- when (isNothing optionsOutputFile && optionsSourceMaps == True) . liftIO $ do- hPutStrLn stderr "psc-bundle: Source maps only supported when output file specified."- exitFailure-- input <- for inputFiles $ \filename -> do- js <- liftIO (readUTF8File filename)- mid <- guessModuleIdentifier filename- length js `seq` return (mid, Just filename, js) -- evaluate readFile till EOF before returning, not to exhaust file handles-- let entryIds = map (`ModuleIdentifier` Regular) optionsEntryPoints-- currentDir <- liftIO getCurrentDirectory- let outFile = if optionsSourceMaps then fmap (currentDir </>) optionsOutputFile else Nothing- bundleSM input entryIds optionsMainModule optionsNamespace outFile---- | Command line options parser.-options :: Parser Options-options = Options <$> some inputFile- <*> optional outputFile- <*> many entryPoint- <*> optional mainModule- <*> namespace- <*> sourceMaps- where- inputFile :: Parser FilePath- inputFile = Opts.strArgument $- Opts.metavar "FILE"- <> Opts.help "The input .js file(s)"-- outputFile :: Parser FilePath- outputFile = Opts.strOption $- Opts.short 'o'- <> Opts.long "output"- <> Opts.help "The output .js file"-- entryPoint :: Parser String- entryPoint = Opts.strOption $- Opts.short 'm'- <> Opts.long "module"- <> Opts.help "Entry point module name(s). All code which is not a transitive dependency of an entry point module will be removed."-- mainModule :: Parser String- mainModule = Opts.strOption $- Opts.long "main"- <> Opts.help "Generate code to run the main method in the specified module."-- namespace :: Parser String- namespace = Opts.strOption $- Opts.short 'n'- <> Opts.long "namespace"- <> Opts.value "PS"- <> Opts.showDefault- <> Opts.help "Specify the namespace that PureScript modules will be exported to when running in the browser."-- sourceMaps :: Parser Bool- sourceMaps = Opts.switch $- Opts.long "source-maps"- <> Opts.help "Whether to generate source maps for the bundle (requires --output)."---- | Make it go.-main :: IO ()-main = do- hSetEncoding stdout utf8- hSetEncoding stderr utf8- opts <- Opts.execParser (Opts.info (version <*> Opts.helper <*> options) infoModList)- output <- runExceptT (app opts)- case output of- Left err -> do- hPutStrLn stderr (unlines (printErrorMessage err))- exitFailure- Right (sourcemap, js) ->- case optionsOutputFile opts of- Just outputFile -> do- createDirectoryIfMissing True (takeDirectory outputFile)- case sourcemap of- Just sm -> do- writeUTF8File outputFile $ js ++ "\n//# sourceMappingURL=" ++ (takeFileName outputFile <.> "map") ++ "\n"- writeUTF8File (outputFile <.> "map") $ BU8.toString . B.toStrict . encode $ generate sm- Nothing -> writeUTF8File outputFile js- Nothing -> putStrLn js- where- infoModList = Opts.fullDesc <> headerInfo <> footerInfo- headerInfo = Opts.header "psc-bundle - Bundles compiled PureScript modules for the browser"- footerInfo = Opts.footer $ "psc-bundle " ++ showVersion Paths.version-- version :: Parser (a -> a)- version = Opts.abortOption (InfoMsg (showVersion Paths.version)) $- Opts.long "version" <> Opts.help "Show the version number" <> Opts.hidden
− psc-docs/Ctags.hs
@@ -1,13 +0,0 @@-module Ctags (dumpCtags) where--import qualified Language.PureScript as P-import Tags-import Data.List (sort)--dumpCtags :: [(String, P.Module)] -> [String]-dumpCtags = sort . concatMap renderModCtags--renderModCtags :: (String, P.Module) -> [String]-renderModCtags (path, mdl) = sort tagLines- where tagLines = map tagLine $ tags mdl- tagLine (name, line) = name ++ "\t" ++ path ++ "\t" ++ show line
− psc-docs/Etags.hs
@@ -1,13 +0,0 @@-module Etags (dumpEtags) where--import qualified Language.PureScript as P-import Tags--dumpEtags :: [(String, P.Module)] -> [String]-dumpEtags = concatMap renderModEtags--renderModEtags :: (String, P.Module) -> [String]-renderModEtags (path, mdl) = ["\x0c", path ++ "," ++ show tagsLen] ++ tagLines- where tagsLen = sum $ map length tagLines- tagLines = map tagLine $ tags mdl- tagLine (name, line) = "\x7f" ++ name ++ "\x01" ++ show line ++ ","
− psc-docs/Main.hs
@@ -1,253 +0,0 @@-{-# LANGUAGE TupleSections #-}--module Main where--import Control.Applicative-import Control.Monad.Trans.Except (runExceptT)-import Control.Arrow (first, second)-import Control.Category ((>>>))-import Control.Monad.Writer-import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.IO as T-import Data.Function (on)-import Data.List-import Data.Maybe (fromMaybe)-import Data.Tuple (swap)-import Data.Version (showVersion)--import Options.Applicative-import qualified Text.PrettyPrint.ANSI.Leijen as PP--import qualified Language.PureScript as P-import qualified Paths_purescript as Paths-import System.Exit (exitFailure)-import System.IO (hPutStrLn, hPrint, hSetEncoding, stderr, stdout, utf8)-import System.IO.UTF8 (readUTF8FileT, writeUTF8FileT)-import System.Directory (createDirectoryIfMissing)-import System.FilePath (takeDirectory)-import System.FilePath.Glob (glob)--import Etags-import Ctags-import qualified Language.PureScript.Docs as D-import qualified Language.PureScript.Docs.AsMarkdown as D---- Available output formats-data Format = Markdown -- Output documentation in Markdown format- | Ctags -- Output ctags symbol index suitable for use with vi- | Etags -- Output etags symbol index suitable for use with emacs- deriving (Show, Eq, Ord)---- | Available methods of outputting Markdown documentation-data DocgenOutput- = EverythingToStdOut- | ToStdOut [P.ModuleName]- | ToFiles [(P.ModuleName, FilePath)]- deriving (Show)--data PSCDocsOptions = PSCDocsOptions- { pscdFormat :: Format- , pscdInputFiles :: [FilePath]- , pscdDocgen :: DocgenOutput- }- deriving (Show)--docgen :: PSCDocsOptions -> IO ()-docgen (PSCDocsOptions fmt inputGlob output) = do- input <- concat <$> mapM glob inputGlob- case fmt of- Etags -> dumpTags input dumpEtags- Ctags -> dumpTags input dumpCtags- Markdown -> do- ms <- runExceptT (D.parseFilesInPackages input []- >>= uncurry D.convertModulesInPackage)- >>= successOrExit-- case output of- EverythingToStdOut ->- T.putStrLn (D.runDocs (D.modulesAsMarkdown ms))- ToStdOut names -> do- let (ms', missing) = takeByName ms names- guardMissing missing- T.putStrLn (D.runDocs (D.modulesAsMarkdown ms'))- ToFiles names -> do- let (ms', missing) = takeByName' ms names- guardMissing missing-- let ms'' = groupBy ((==) `on` fst) . sortBy (compare `on` fst) $ map swap ms'- forM_ ms'' $ \grp -> do- let fp = fst (head grp)- createDirectoryIfMissing True (takeDirectory fp)- writeUTF8FileT fp (D.runDocs (D.modulesAsMarkdown (map snd grp)))-- where- guardMissing [] = return ()- guardMissing [mn] = do- hPutStrLn stderr ("psc-docs: error: unknown module \"" ++ T.unpack (P.runModuleName mn) ++ "\"")- exitFailure- guardMissing mns = do- hPutStrLn stderr "psc-docs: error: unknown modules:"- forM_ mns $ \mn ->- hPutStrLn stderr (" * " ++ T.unpack (P.runModuleName mn))- exitFailure-- successOrExit :: Either P.MultipleErrors a -> IO a- successOrExit act =- case act of- Right x ->- return x- Left err -> do- hPutStrLn stderr $ P.prettyPrintMultipleErrors P.defaultPPEOptions err- exitFailure-- takeByName = takeModulesByName D.modName- takeByName' = takeModulesByName' D.modName---- |--- Given a list of module names and a list of modules, return a list of modules--- whose names appeared in the given name list, together with a list of names--- for which no module could be found in the module list.----takeModulesByName :: (Eq n) => (m -> n) -> [m] -> [n] -> ([m], [n])-takeModulesByName getModuleName modules names =- first (map fst) (takeModulesByName' getModuleName modules (map (,()) names))---- |--- Like takeModulesByName, but also keeps some extra information with each--- module.----takeModulesByName' :: (Eq n) => (m -> n) -> [m] -> [(n, a)] -> ([(m, a)], [n])-takeModulesByName' getModuleName modules = foldl go ([], [])- where- go (ms, missing) (name, x) =- case find ((== name) . getModuleName) modules of- Just m -> ((m, x) : ms, missing)- Nothing -> (ms, name : missing)--dumpTags :: [FilePath] -> ([(String, P.Module)] -> [String]) -> IO ()-dumpTags input renderTags = do- e <- P.parseModulesFromFiles (fromMaybe "") <$> mapM (fmap (first Just) . parseFile) (nub input)- case e of- Left err -> do- hPrint stderr err- exitFailure- Right ms ->- ldump (renderTags (pairs ms))-- where- pairs :: [(Maybe String, m)] -> [(String, m)]- pairs = map (first (fromMaybe ""))-- ldump :: [String] -> IO ()- ldump = mapM_ putStrLn--parseFile :: FilePath -> IO (FilePath, Text)-parseFile input = (,) input <$> readUTF8FileT input--inputFile :: Parser FilePath-inputFile = strArgument $- metavar "FILE"- <> help "The input .purs file(s)"--instance Read Format where- readsPrec _ "etags" = [(Etags, "")]- readsPrec _ "ctags" = [(Ctags, "")]- readsPrec _ "markdown" = [(Markdown, "")]- readsPrec _ _ = []--format :: Parser Format-format = option auto $ value Markdown- <> long "format"- <> metavar "FORMAT"- <> help "Set output FORMAT (markdown | etags | ctags)"--docgenModule :: Parser String-docgenModule = strOption $- long "docgen"- <> help "A list of module names which should appear in the output. This can optionally include file paths to write individual modules to, by separating with a colon ':'. For example, Prelude:docs/Prelude.md. This option may be specified multiple times."--pscDocsOptions :: Parser (Format, [FilePath], [String])-pscDocsOptions = (,,) <$> format <*> many inputFile <*> many docgenModule--parseDocgen :: [String] -> Either String DocgenOutput-parseDocgen [] = Right EverythingToStdOut-parseDocgen xs = go xs- where- go = intersperse " "- >>> concat- >>> words- >>> map parseItem- >>> combine--data DocgenOutputItem- = IToStdOut P.ModuleName- | IToFile (P.ModuleName, FilePath)--parseItem :: String -> DocgenOutputItem-parseItem s = case elemIndex ':' s of- Just i ->- s # splitAt i- >>> first (P.moduleNameFromString . T.pack)- >>> second (drop 1)- >>> IToFile- Nothing ->- IToStdOut (P.moduleNameFromString (T.pack s))-- where- infixr 1 #- (#) = flip ($)--combine :: [DocgenOutputItem] -> Either String DocgenOutput-combine [] = Right EverythingToStdOut-combine (x:xs) = foldM go (initial x) xs- where- initial (IToStdOut m) = ToStdOut [m]- initial (IToFile m) = ToFiles [m]-- go (ToStdOut ms) (IToStdOut m) = Right (ToStdOut (m:ms))- go (ToFiles ms) (IToFile m) = Right (ToFiles (m:ms))- go _ _ = Left "Can't mix module names and module name/file path pairs in the same invocation."--buildOptions :: (Format, [FilePath], [String]) -> IO PSCDocsOptions-buildOptions (fmt, input, mapping) =- case parseDocgen mapping of- Right mapping' -> return (PSCDocsOptions fmt input mapping')- Left err -> do- hPutStrLn stderr "psc-docs: error in --docgen option:"- hPutStrLn stderr (" " ++ err)- exitFailure--main :: IO ()-main = do- hSetEncoding stdout utf8- hSetEncoding stderr utf8- execParser opts >>= buildOptions >>= docgen- where- opts = info (version <*> helper <*> pscDocsOptions) infoModList- infoModList = fullDesc <> headerInfo <> footerInfo- headerInfo = header "psc-docs - Generate Markdown documentation from PureScript source files"- footerInfo = footerDoc $ Just $ PP.vcat- [ examples, PP.empty, PP.text ("psc-docs " ++ showVersion Paths.version) ]-- version :: Parser (a -> a)- version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden--examples :: PP.Doc-examples =- PP.vcat $ map PP.text- [ "Examples:"- , " print documentation for Data.List to stdout:"- , " psc-docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"- , " --docgen Data.List"- , ""- , " write documentation for Data.List to docs/Data.List.md:"- , " psc-docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"- , " --docgen Data.List:docs/Data.List.md"- , ""- , " write documentation for Data.List to docs/Data.List.md, and"- , " documentation for Data.List.Lazy to docs/Data.List.Lazy.md:"- , " psc-docs \"src/**/*.purs\" \".psc-package/*/*/*/src/**/*.purs\" \\"- , " --docgen Data.List:docs/Data.List.md \\"- , " --docgen Data.List.Lazy:docs/Data.List.Lazy.md"- ]
− psc-docs/Tags.hs
@@ -1,21 +0,0 @@-module Tags where--import Control.Arrow (first)-import qualified Data.Text as T-import qualified Language.PureScript as P--tags :: P.Module -> [(String, Int)]-tags = map (first T.unpack) . concatMap dtags . P.exportedDeclarations- where dtags (P.PositionedDeclaration sp _ d) = map tag $ names d- where tag name = (name, line)- line = P.sourcePosLine $ P.spanStart sp- dtags _ = []- names (P.DataDeclaration _ name _ dcons) = P.runProperName name : consNames- where consNames = map (\(cname, _) -> P.runProperName cname) dcons- names (P.TypeDeclaration ident _) = [P.showIdent ident]- names (P.ExternDeclaration ident _) = [P.showIdent ident]- names (P.TypeSynonymDeclaration name _ _) = [P.runProperName name]- names (P.TypeClassDeclaration name _ _ _ _) = [P.runProperName name]- names (P.TypeInstanceDeclaration name _ _ _ _) = [P.showIdent name]- names (P.ExternKindDeclaration name) = [P.runProperName name]- names _ = []
− psc-ide-client/Main.hs
@@ -1,50 +0,0 @@-module Main where--import Prelude ()-import Prelude.Compat--import Control.Exception-import qualified Data.ByteString.Char8 as BS8-import qualified Data.Text.IO as T-import Data.Version (showVersion)-import Data.Monoid ((<>))-import Network-import Options.Applicative (ParseError (..))-import qualified Options.Applicative as Opts-import System.Exit-import System.IO--import qualified Paths_purescript as Paths--data Options = Options- { optionsPort :: PortID- }--main :: IO ()-main = do- Options port <- Opts.execParser opts- client port- where- parser =- Options <$>- (PortNumber . fromIntegral <$>- Opts.option Opts.auto (Opts.long "port" <> Opts.short 'p' <> Opts.value (4242 :: Integer)))- opts = Opts.info (version <*> Opts.helper <*> parser) mempty- version = Opts.abortOption (InfoMsg (showVersion Paths.version)) $- Opts.long "version" <> Opts.help "Show the version number" <> Opts.hidden--client :: PortID -> IO ()-client port = do- hSetEncoding stdin utf8- hSetEncoding stdout utf8- h <-- connectTo "127.0.0.1" port `catch`- (\(SomeException e) ->- putStrLn- ("Couldn't connect to psc-ide-server on port: " ++- show port ++ " Error: " ++ show e) >>- exitFailure)- T.hPutStrLn h =<< T.getLine- BS8.putStrLn =<< BS8.hGetLine h- hFlush stdout- hClose h
− psc-ide-server/Main.hs
@@ -1,187 +0,0 @@------------------------------------------------------------------------------------ Module : Main--- Description : The server accepting commands for psc-ide--- Copyright : Christoph Hegemann 2016--- License : MIT (http://opensource.org/licenses/MIT)------ Maintainer : Christoph Hegemann <christoph.hegemann1337@gmail.com>--- Stability : experimental------ |--- The server accepting commands for psc-ide--------------------------------------------------------------------------------{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE NoImplicitPrelude #-}--module Main where--import Protolude--import qualified Data.Aeson as Aeson-import Control.Concurrent.STM-import "monad-logger" Control.Monad.Logger-import qualified Data.Text.IO as T-import qualified Data.ByteString.Lazy.Char8 as BS8-import Data.Version (showVersion)-import GHC.IO.Exception (IOErrorType(..), IOException(..))-import Language.PureScript.Ide-import Language.PureScript.Ide.Command-import Language.PureScript.Ide.Util-import Language.PureScript.Ide.Error-import Language.PureScript.Ide.Types-import Language.PureScript.Ide.Watcher-import Network hiding (socketPort, accept)-import Network.BSD (getProtocolNumber)-import Network.Socket hiding (PortNumber, Type,- sClose)-import Options.Applicative (ParseError (..))-import qualified Options.Applicative as Opts-import System.Directory-import System.Info as SysInfo-import System.FilePath-import System.IO hiding (putStrLn, print)-import System.IO.Error (isEOFError)-import qualified Paths_purescript as Paths--listenOnLocalhost :: PortNumber -> IO Socket-listenOnLocalhost port = do- proto <- getProtocolNumber "tcp"- localhost <- inet_addr "127.0.0.1"- bracketOnError- (socket AF_INET Stream proto)- sClose- (\sock -> do- setSocketOption sock ReuseAddr 1- bind sock (SockAddrInet port localhost)- listen sock maxListenQueue- pure sock)--data Options = Options- { optionsDirectory :: Maybe FilePath- , optionsGlobs :: [FilePath]- , optionsOutputPath :: FilePath- , optionsPort :: PortNumber- , optionsNoWatch :: Bool- , optionsPolling :: Bool- , optionsDebug :: Bool- , optionsLoglevel :: IdeLogLevel- } deriving (Show)--main :: IO ()-main = do- opts'@(Options dir globs outputPath port noWatch polling debug logLevel) <- Opts.execParser opts- when debug (putText "Parsed Options:" *> print opts')- maybe (pure ()) setCurrentDirectory dir- ideState <- newTVarIO emptyIdeState- cwd <- getCurrentDirectory- let fullOutputPath = cwd </> outputPath-- unlessM (doesDirectoryExist fullOutputPath) $ do- putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)- createDirectory fullOutputPath- putText "This usually means you didn't compile your project yet."- putText "psc-ide needs you to compile your project (for example by running pulp build)"-- unless noWatch $- void (forkFinally (watcher polling ideState fullOutputPath) print)- -- TODO: deprecate and get rid of `debug`- let conf = Configuration {confLogLevel = if debug then LogDebug else logLevel, confOutputPath = outputPath, confGlobs = globs}- env = IdeEnvironment {ideStateVar = ideState, ideConfiguration = conf}- startServer port env- where- parser =- Options- <$> optional (Opts.strOption (Opts.long "directory" `mappend` Opts.short 'd'))- <*> many (Opts.argument Opts.str (Opts.metavar "Source GLOBS..."))- <*> Opts.strOption (Opts.long "output-directory" `mappend` Opts.value "output/")- <*> (fromIntegral <$>- Opts.option Opts.auto (Opts.long "port" `mappend` Opts.short 'p' `mappend` Opts.value (4242 :: Integer)))- <*> Opts.switch (Opts.long "no-watch")- <*> flipIfWindows (Opts.switch (Opts.long "polling"))- <*> Opts.switch (Opts.long "debug")- <*> (parseLogLevel <$> Opts.strOption- (Opts.long "log-level"- `mappend` Opts.value ""- `mappend` Opts.help "One of \"debug\", \"perf\", \"all\" or \"none\""))- opts = Opts.info (version <*> Opts.helper <*> parser) mempty- parseLogLevel s = case s of- "debug" -> LogDebug- "perf" -> LogPerf- "all" -> LogAll- "none" -> LogNone- _ -> LogDefault- version = Opts.abortOption- (InfoMsg (showVersion Paths.version))- (Opts.long "version" `mappend` Opts.help "Show the version number")-- -- polling is the default on Windows and the flag turns it off. See- -- #2209 and #2414 for explanations- flipIfWindows = map (if SysInfo.os == "mingw32" then not else identity)--startServer :: PortNumber -> IdeEnvironment -> IO ()-startServer port env = withSocketsDo $ do- sock <- listenOnLocalhost port- runLogger (confLogLevel (ideConfiguration env)) (runReaderT (forever (loop sock)) env)- where- loop :: (Ide m, MonadLogger m) => Socket -> m ()- loop sock = do- accepted <- runExceptT (acceptCommand sock)- case accepted of- Left err -> $(logError) err- Right (cmd, h) -> do- case decodeT cmd of- Just cmd' -> do- let message duration =- "Command " <> commandName cmd'- <> " took "- <> displayTimeSpec duration- result <- logPerf message (runExceptT (handleCommand cmd'))- -- $(logDebug) ("Answer was: " <> T.pack (show result))- liftIO (hFlush stdout)- case result of- Right r -> liftIO $ catchGoneHandle (BS8.hPutStrLn h (Aeson.encode r))- Left err -> liftIO $ catchGoneHandle (BS8.hPutStrLn h (Aeson.encode err))- Nothing -> do- $(logError) ("Parsing the command failed. Command: " <> cmd)- liftIO $ do- catchGoneHandle (T.hPutStrLn h (encodeT (GeneralError "Error parsing Command.")))- hFlush stdout- liftIO $ catchGoneHandle (hClose h)--catchGoneHandle :: IO () -> IO ()-catchGoneHandle =- handle (\e -> case e of- IOError { ioe_type = ResourceVanished } ->- putText ("[Error] psc-ide-server tried interact with the handle, but the connection was already gone.")- _ -> throwIO e)--acceptCommand :: (MonadIO m, MonadLogger m, MonadError Text m)- => Socket -> m (Text, Handle)-acceptCommand sock = do- h <- acceptConnection- $(logDebug) "Accepted a connection"- cmd' <- liftIO (catchJust- -- this means that the connection was- -- terminated without receiving any input- (\e -> if isEOFError e then Just () else Nothing)- (Just <$> T.hGetLine h)- (const (pure Nothing)))- case cmd' of- Nothing -> throwError "Connection was closed before any input arrived"- Just cmd -> do- $(logDebug) ("Received command: " <> cmd)- pure (cmd, h)- where- acceptConnection = liftIO $ do- -- Use low level accept to prevent accidental reverse name resolution- (s,_) <- accept sock- h <- socketToHandle s ReadWriteMode- hSetEncoding h utf8- hSetBuffering h LineBuffering- pure h
− psc-package/Main.hs
@@ -1,423 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}--module Main where--import qualified Control.Foldl as Foldl-import qualified Data.Aeson as Aeson-import Data.Aeson.Encode.Pretty-import Data.Foldable (fold, for_, traverse_)-import Data.List (nub)-import qualified Data.Map as Map-import Data.Maybe (fromMaybe, mapMaybe)-import qualified Data.Set as Set-import Data.Text (pack)-import qualified Data.Text as T-import Data.Text.Encoding (encodeUtf8)-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as TB-import qualified Data.Text.Read as TR-import Data.Traversable (for)-import Data.Version (showVersion)-import qualified Filesystem.Path.CurrentOS as Path-import GHC.Generics (Generic)-import qualified Options.Applicative as Opts-import qualified Paths_purescript as Paths-import qualified System.IO as IO-import Turtle hiding (echo, fold, s, x)-import qualified Turtle--echoT :: Text -> IO ()-echoT = Turtle.printf (Turtle.s % "\n")--packageFile :: Path.FilePath-packageFile = "psc-package.json"--data PackageConfig = PackageConfig- { name :: Text- , depends :: [Text]- , set :: Text- , source :: Text- } deriving (Show, Generic, Aeson.FromJSON, Aeson.ToJSON)--pathToTextUnsafe :: Turtle.FilePath -> Text-pathToTextUnsafe = either (error "Path.toText failed") id . Path.toText--defaultPackage :: Text -> PackageConfig-defaultPackage pkgName =- PackageConfig { name = pkgName- , depends = [ "prelude" ]- , set = "psc-" <> pack (showVersion Paths.version)- , source = "https://github.com/purescript/package-sets.git"- }--readPackageFile :: IO PackageConfig-readPackageFile = do- exists <- testfile packageFile- unless exists $ do- echoT "psc-package.json does not exist"- exit (ExitFailure 1)- mpkg <- Aeson.decodeStrict . encodeUtf8 <$> readTextFile packageFile- case mpkg of- Nothing -> do- echoT "Unable to parse psc-package.json"- exit (ExitFailure 1)- Just pkg -> return pkg--packageConfigToJSON :: PackageConfig -> Text-packageConfigToJSON =- TL.toStrict- . TB.toLazyText- . encodePrettyToTextBuilder' config- where- config = defConfig- { confCompare =- keyOrder [ "name"- , "set"- , "source"- , "depends"- ]- }--packageSetToJSON :: PackageSet -> Text-packageSetToJSON =- TL.toStrict- . TB.toLazyText- . encodePrettyToTextBuilder' config- where- config = defConfig { confCompare = compare }--writePackageFile :: PackageConfig -> IO ()-writePackageFile =- writeTextFile packageFile- . packageConfigToJSON--data PackageInfo = PackageInfo- { repo :: Text- , version :: Text- , dependencies :: [Text]- } deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)--type PackageSet = Map.Map Text PackageInfo--cloneShallow- :: Text- -- ^ repo- -> Text- -- ^ branch/tag- -> Turtle.FilePath- -- ^ target directory- -> IO ExitCode-cloneShallow from ref into =- proc "git"- [ "clone"- , "-q"- , "-c", "advice.detachedHead=false"- , "--depth", "1"- , "-b", ref- , from- , pathToTextUnsafe into- ] empty .||. exit (ExitFailure 1)--listRemoteTags- :: Text- -- ^ repo- -> Turtle.Shell Text-listRemoteTags from = let gitProc = inproc "git"- [ "ls-remote"- , "-q"- , "-t"- , from- ] empty- in lineToText <$> gitProc--getPackageSet :: PackageConfig -> IO ()-getPackageSet PackageConfig{ source, set } = do- let pkgDir = ".psc-package" </> fromText set </> ".set"- exists <- testdir pkgDir- unless exists . void $ cloneShallow source set pkgDir--readPackageSet :: PackageConfig -> IO PackageSet-readPackageSet PackageConfig{ set } = do- let dbFile = ".psc-package" </> fromText set </> ".set" </> "packages.json"- exists <- testfile dbFile- unless exists $ do- echoT $ format (fp%" does not exist") dbFile- exit (ExitFailure 1)- mdb <- Aeson.decodeStrict . encodeUtf8 <$> readTextFile dbFile- case mdb of- Nothing -> do- echoT "Unable to parse packages.json"- exit (ExitFailure 1)- Just db -> return db--writePackageSet :: PackageConfig -> PackageSet -> IO ()-writePackageSet PackageConfig{ set } =- let dbFile = ".psc-package" </> fromText set </> ".set" </> "packages.json"- in writeTextFile dbFile . packageSetToJSON--installOrUpdate :: Text -> Text -> PackageInfo -> IO Turtle.FilePath-installOrUpdate set pkgName PackageInfo{ repo, version } = do- echoT ("Updating " <> pkgName)- let pkgDir = ".psc-package" </> fromText set </> fromText pkgName </> fromText version- exists <- testdir pkgDir- unless exists . void $ cloneShallow repo version pkgDir- pure pkgDir--getTransitiveDeps :: PackageSet -> [Text] -> IO [(Text, PackageInfo)]-getTransitiveDeps db depends = do- pkgs <- for depends $ \pkg ->- case Map.lookup pkg db of- Nothing -> do- echoT ("Package " <> pkg <> " does not exist in package set")- exit (ExitFailure 1)- Just PackageInfo{ dependencies } -> return (pkg : dependencies)- let unique = Set.toList (foldMap Set.fromList pkgs)- return (mapMaybe (\name -> fmap (name, ) (Map.lookup name db)) unique)--updateImpl :: PackageConfig -> IO ()-updateImpl config@PackageConfig{ depends } = do- getPackageSet config- db <- readPackageSet config- trans <- getTransitiveDeps db depends- echoT ("Updating " <> pack (show (length trans)) <> " packages...")- for_ trans $ \(pkgName, pkg) -> installOrUpdate (set config) pkgName pkg--initialize :: IO ()-initialize = do- exists <- testfile "psc-package.json"- when exists $ do- echoT "psc-package.json already exists"- exit (ExitFailure 1)- echoT "Initializing new project in current directory"- pkgName <- pathToTextUnsafe . Path.filename <$> pwd- let pkg = defaultPackage pkgName- writePackageFile pkg- updateImpl pkg--update :: IO ()-update = do- pkg <- readPackageFile- updateImpl pkg- echoT "Update complete"--install :: String -> IO ()-install pkgName = do- pkg <- readPackageFile- let pkg' = pkg { depends = nub (pack pkgName : depends pkg) }- updateImpl pkg'- writePackageFile pkg'- echoT "psc-package.json file was updated"--uninstall :: String -> IO ()-uninstall pkgName = do- pkg <- readPackageFile- let pkg' = pkg { depends = filter (/= pack pkgName) $ depends pkg }- updateImpl pkg'- writePackageFile pkg'- echoT "psc-package.json file was updated"--listDependencies :: IO ()-listDependencies = do- pkg@PackageConfig{ depends } <- readPackageFile- db <- readPackageSet pkg- trans <- getTransitiveDeps db depends- traverse_ (echoT . fst) trans--listPackages :: IO ()-listPackages = do- pkg <- readPackageFile- db <- readPackageSet pkg- traverse_ echoT (fmt <$> Map.assocs db)- where- fmt :: (Text, PackageInfo) -> Text- fmt (name, PackageInfo{ version }) = name <> " (" <> version <> ")"--getSourcePaths :: PackageConfig -> PackageSet -> [Text] -> IO [Turtle.FilePath]-getSourcePaths PackageConfig{..} db pkgNames = do- trans <- getTransitiveDeps db pkgNames- let paths = [ ".psc-package"- </> fromText set- </> fromText pkgName- </> fromText version- </> "src" </> "**" </> "*.purs"- | (pkgName, PackageInfo{ version }) <- trans- ]- return paths--listSourcePaths :: IO ()-listSourcePaths = do- pkg@PackageConfig{ depends } <- readPackageFile- db <- readPackageSet pkg- paths <- getSourcePaths pkg db depends- traverse_ (echoT . pathToTextUnsafe) paths--exec :: Text -> IO ()-exec exeName = do- pkg@PackageConfig{..} <- readPackageFile- db <- readPackageSet pkg- paths <- getSourcePaths pkg db depends- procs exeName- (map pathToTextUnsafe ("src" </> "**" </> "*.purs" : paths))- empty--checkForUpdates :: Bool -> Bool -> IO ()-checkForUpdates applyMinorUpdates applyMajorUpdates = do- pkg <- readPackageFile- db <- readPackageSet pkg-- echoT ("Checking " <> pack (show (Map.size db)) <> " packages for updates.")- echoT "Warning: this could take some time!"-- newDb <- Map.fromList <$> (for (Map.toList db) $ \(name, p@PackageInfo{ repo, version }) -> do- echoT ("Checking package " <> name)- tagLines <- Turtle.fold (listRemoteTags repo) Foldl.list- let tags = mapMaybe parseTag tagLines- newVersion <- case parseVersion version of- Just parts ->- let applyMinor =- case filter (isMinorReleaseFrom parts) tags of- [] -> pure version- minorReleases -> do- echoT ("New minor release available")- case applyMinorUpdates of- True -> do- let latestMinorRelease = maximum minorReleases- pure ("v" <> T.intercalate "." (map (pack . show) latestMinorRelease))- False -> pure version- applyMajor =- case filter (isMajorReleaseFrom parts) tags of- [] -> applyMinor- newReleases -> do- echoT ("New major release available")- case applyMajorUpdates of- True -> do- let latestRelease = maximum newReleases- pure ("v" <> T.intercalate "." (map (pack . show) latestRelease))- False -> applyMinor- in applyMajor- _ -> do- echoT "Unable to parse version string"- pure version- pure (name, p { version = newVersion }))-- when (applyMinorUpdates || applyMajorUpdates)- (writePackageSet pkg newDb)- where- parseTag :: Text -> Maybe [Int]- parseTag line =- case T.splitOn "\t" line of- [_sha, ref] ->- case T.stripPrefix "refs/tags/" ref of- Just tag ->- case parseVersion tag of- Just parts -> pure parts- _ -> Nothing- _ -> Nothing- _ -> Nothing-- parseVersion :: Text -> Maybe [Int]- parseVersion ref =- case T.stripPrefix "v" ref of- Just tag ->- traverse parseDecimal (T.splitOn "." tag)- _ -> Nothing-- parseDecimal :: Text -> Maybe Int- parseDecimal s =- case TR.decimal s of- Right (n, "") -> Just n- _ -> Nothing-- isMajorReleaseFrom :: [Int] -> [Int] -> Bool- isMajorReleaseFrom (0 : xs) (0 : ys) = isMajorReleaseFrom xs ys- isMajorReleaseFrom (x : _) (y : _) = y > x- isMajorReleaseFrom _ _ = False-- isMinorReleaseFrom :: [Int] -> [Int] -> Bool- isMinorReleaseFrom (0 : xs) (0 : ys) = isMinorReleaseFrom xs ys- isMinorReleaseFrom (x : xs) (y : ys) = y == x && ys > xs- isMinorReleaseFrom _ _ = False--verifyPackageSet :: IO ()-verifyPackageSet = do- pkg <- readPackageFile- db <- readPackageSet pkg-- echoT ("Verifying " <> pack (show (Map.size db)) <> " packages.")- echoT "Warning: this could take some time!"-- let installOrUpdate' (name, pkgInfo) = (name, ) <$> installOrUpdate (set pkg) name pkgInfo- paths <- Map.fromList <$> traverse installOrUpdate' (Map.toList db)-- for_ (Map.toList db) $ \(name, PackageInfo{..}) -> do- let dirFor = fromMaybe (error "verifyPackageSet: no directory") . (`Map.lookup` paths)- echoT ("Verifying package " <> name)- let srcGlobs = map (pathToTextUnsafe . (</> ("src" </> "**" </> "*.purs")) . dirFor) (name : dependencies)- procs "psc" srcGlobs empty--main :: IO ()-main = do- IO.hSetEncoding IO.stdout IO.utf8- IO.hSetEncoding IO.stderr IO.utf8- cmd <- Opts.execParser opts- cmd- where- opts = Opts.info (versionInfo <*> Opts.helper <*> commands) infoModList- infoModList = Opts.fullDesc <> headerInfo <> footerInfo- headerInfo = Opts.progDesc "Manage package dependencies"- footerInfo = Opts.footer $ "psc-package " ++ showVersion Paths.version-- versionInfo :: Parser (a -> a)- versionInfo = Opts.abortOption (Opts.InfoMsg (showVersion Paths.version)) $- Opts.long "version" <> Opts.help "Show the version number" <> Opts.hidden-- commands :: Parser (IO ())- commands = (Opts.subparser . fold)- [ Opts.command "init"- (Opts.info (pure initialize)- (Opts.progDesc "Initialize a new package"))- , Opts.command "update"- (Opts.info (pure update)- (Opts.progDesc "Update dependencies"))- , Opts.command "uninstall"- (Opts.info (uninstall <$> pkg)- (Opts.progDesc "Uninstall the named package"))- , Opts.command "install"- (Opts.info (install <$> pkg)- (Opts.progDesc "Install the named package"))- , Opts.command "build"- (Opts.info (pure (exec "psc"))- (Opts.progDesc "Build the current package and dependencies"))- , Opts.command "dependencies"- (Opts.info (pure listDependencies)- (Opts.progDesc "List all (transitive) dependencies for the current package"))- , Opts.command "sources"- (Opts.info (pure listSourcePaths)- (Opts.progDesc "List all (active) source paths for dependencies"))- , Opts.command "available"- (Opts.info (pure listPackages)- (Opts.progDesc "List all packages available in the package set"))- , Opts.command "updates"- (Opts.info (checkForUpdates <$> apply <*> applyMajor)- (Opts.progDesc "Check all packages in the package set for new releases"))- , Opts.command "verify-set"- (Opts.info (pure verifyPackageSet)- (Opts.progDesc "Verify that the packages in the package set build correctly"))- ]- where- pkg = Opts.strArgument $- Opts.metavar "PACKAGE"- <> Opts.help "The name of the package to install"-- apply = Opts.switch $- Opts.long "apply"- <> Opts.help "Apply all minor package updates"-- applyMajor = Opts.switch $- Opts.long "apply-breaking"- <> Opts.help "Apply all major package updates"
− psc-publish/Main.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Main where--import Control.Monad.IO.Class (liftIO)-import Data.Version (Version(..), showVersion)-import qualified Data.Aeson as A-import qualified Data.ByteString.Lazy.Char8 as BL-import Data.Monoid ((<>))-import Data.Time.Clock (getCurrentTime)--import Options.Applicative (Parser, ParseError (..))-import qualified Options.Applicative as Opts--import System.IO (hSetEncoding, stderr, stdout, utf8)--import qualified Paths_purescript as Paths-import Language.PureScript.Publish-import Language.PureScript.Publish.ErrorsWarnings--dryRun :: Parser Bool-dryRun = Opts.switch $- Opts.long "dry-run"- <> Opts.help "Produce no output, and don't require a tagged version to be checked out."--dryRunOptions :: PublishOptions-dryRunOptions = defaultPublishOptions- { publishGetVersion = return dummyVersion- , publishWorkingTreeDirty = warn DirtyWorkingTree_Warn- , publishGetTagTime = const (liftIO getCurrentTime)- }- where dummyVersion = ("0.0.0", Version [0,0,0] [])--main :: IO ()-main = do- hSetEncoding stdout utf8- hSetEncoding stderr utf8- Opts.execParser opts >>= publish- where- opts = Opts.info (version <*> Opts.helper <*> dryRun) infoModList- infoModList = Opts.fullDesc <> headerInfo <> footerInfo- headerInfo = Opts.header "psc-publish - Generates documentation packages for upload to http://pursuit.purescript.org"- footerInfo = Opts.footer $ "psc-publish " ++ showVersion Paths.version-- version :: Parser (a -> a)- version = Opts.abortOption (InfoMsg (showVersion Paths.version)) $- Opts.long "version" <> Opts.help "Show the version number" <> Opts.hidden--publish :: Bool -> IO ()-publish isDryRun =- if isDryRun- then do- _ <- unsafePreparePackage dryRunOptions- putStrLn "Dry run completed, no errors."- else do- pkg <- unsafePreparePackage defaultPublishOptions- BL.putStrLn (A.encode pkg)
− psc/Main.hs
@@ -1,182 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}--module Main where--import Control.Applicative-import Control.Monad-import Control.Monad.Writer.Strict--import qualified Data.Aeson as A-import Data.Bool (bool)-import qualified Data.ByteString.Lazy as B-import qualified Data.ByteString.UTF8 as BU8-import qualified Data.Map as M-import Data.Text (Text)-import Data.Version (showVersion)--import qualified Language.PureScript as P-import Language.PureScript.Errors.JSON-import Language.PureScript.Make--import Options.Applicative as Opts--import qualified Paths_purescript as Paths--import qualified System.Console.ANSI as ANSI-import System.Exit (exitSuccess, exitFailure)-import System.FilePath.Glob (glob)-import System.IO (hSetEncoding, hPutStrLn, stdout, stderr, utf8)-import System.IO.UTF8 (readUTF8FileT)--data PSCMakeOptions = PSCMakeOptions- { pscmInput :: [FilePath]- , pscmOutputDir :: FilePath- , pscmOpts :: P.Options- , pscmUsePrefix :: Bool- , pscmJSONErrors :: Bool- }---- | Argumnets: verbose, use JSON, warnings, errors-printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()-printWarningsAndErrors verbose False warnings errors = do- cc <- bool Nothing (Just P.defaultCodeColor) <$> ANSI.hSupportsANSI stderr- let ppeOpts = P.defaultPPEOptions { P.ppeCodeColor = cc, P.ppeFull = verbose }- when (P.nonEmpty warnings) $- hPutStrLn stderr (P.prettyPrintMultipleWarnings ppeOpts warnings)- case errors of- Left errs -> do- hPutStrLn stderr (P.prettyPrintMultipleErrors ppeOpts errs)- exitFailure- Right _ -> return ()-printWarningsAndErrors verbose True warnings errors = do- hPutStrLn stderr . BU8.toString . B.toStrict . A.encode $- JSONResult (toJSONErrors verbose P.Warning warnings)- (either (toJSONErrors verbose P.Error) (const []) errors)- either (const exitFailure) (const (return ())) errors--compile :: PSCMakeOptions -> IO ()-compile PSCMakeOptions{..} = do- input <- globWarningOnMisses (unless pscmJSONErrors . warnFileTypeNotFound) pscmInput- when (null input && not pscmJSONErrors) $ do- hPutStrLn stderr "psc: No input files."- exitFailure- moduleFiles <- readInput input- (makeErrors, makeWarnings) <- runMake pscmOpts $ do- ms <- P.parseModulesFromFiles id moduleFiles- let filePathMap = M.fromList $ map (\(fp, P.Module _ _ mn _ _) -> (mn, Right fp)) ms- foreigns <- inferForeignModules filePathMap- let makeActions = buildMakeActions pscmOutputDir filePathMap foreigns pscmUsePrefix- P.make makeActions (map snd ms)- printWarningsAndErrors (P.optionsVerboseErrors pscmOpts) pscmJSONErrors makeWarnings makeErrors- exitSuccess--warnFileTypeNotFound :: String -> IO ()-warnFileTypeNotFound = hPutStrLn stderr . ("psc: No files found using pattern: " ++)--globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath]-globWarningOnMisses warn = concatMapM globWithWarning- where- globWithWarning pattern' = do- paths <- glob pattern'- when (null paths) $ warn pattern'- return paths- concatMapM f = fmap concat . mapM f--readInput :: [FilePath] -> IO [(FilePath, Text)]-readInput inputFiles = forM inputFiles $ \inFile -> (inFile, ) <$> readUTF8FileT inFile--inputFile :: Parser FilePath-inputFile = strArgument $- metavar "FILE"- <> help "The input .purs file(s)"--outputDirectory :: Parser FilePath-outputDirectory = strOption $- short 'o'- <> long "output"- <> Opts.value "output"- <> showDefault- <> help "The output directory"--noTco :: Parser Bool-noTco = switch $- long "no-tco"- <> help "Disable tail call optimizations"--noMagicDo :: Parser Bool-noMagicDo = switch $- long "no-magic-do"- <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad"--noOpts :: Parser Bool-noOpts = switch $- long "no-opts"- <> help "Skip the optimization phase"--comments :: Parser Bool-comments = switch $- short 'c'- <> long "comments"- <> help "Include comments in the generated code"--verboseErrors :: Parser Bool-verboseErrors = switch $- short 'v'- <> long "verbose-errors"- <> help "Display verbose error messages"--noPrefix :: Parser Bool-noPrefix = switch $- short 'p'- <> long "no-prefix"- <> help "Do not include comment header"--jsonErrors :: Parser Bool-jsonErrors = switch $- long "json-errors"- <> help "Print errors to stderr as JSON"-sourceMaps :: Parser Bool-sourceMaps = switch $- long "source-maps"- <> help "Generate source maps"--dumpCoreFn :: Parser Bool-dumpCoreFn = switch $- long "dump-corefn"- <> help "Dump the (functional) core representation of the compiled code at output/*/corefn.json"---options :: Parser P.Options-options = P.Options <$> noTco- <*> noMagicDo- <*> pure Nothing- <*> noOpts- <*> verboseErrors- <*> (not <$> comments)- <*> sourceMaps- <*> dumpCoreFn--pscMakeOptions :: Parser PSCMakeOptions-pscMakeOptions = PSCMakeOptions <$> many inputFile- <*> outputDirectory- <*> options- <*> (not <$> noPrefix)- <*> jsonErrors--main :: IO ()-main = do- hSetEncoding stdout utf8- hSetEncoding stderr utf8- execParser opts >>= compile- where- opts = info (version <*> helper <*> pscMakeOptions) infoModList- infoModList = fullDesc <> headerInfo <> footerInfo- headerInfo = header "psc - Compiles PureScript to Javascript"- footerInfo = footer $ "psc " ++ showVersion Paths.version-- version :: Parser (a -> a)- version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
− psci/Main.hs
@@ -1,377 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DoAndIfThenElse #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PatternGuards #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TupleSections #-}--module Main (main) where--import Prelude ()-import Prelude.Compat--import Data.FileEmbed (embedStringFile)-import Data.Monoid ((<>))-import Data.String (IsString(..))-import Data.Text (Text, unpack)-import Data.Traversable (for)-import Data.Version (showVersion)--import Control.Applicative (many, (<|>))-import Control.Concurrent (forkIO)-import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar,- tryPutMVar)-import Control.Concurrent.STM (TVar, atomically, newTVarIO, writeTVar,- readTVarIO,- TChan, newBroadcastTChanIO, dupTChan,- readTChan, writeTChan)-import Control.Exception (fromException)-import Control.Monad-import Control.Monad.IO.Class (liftIO)-import Control.Monad.Trans.Class-import Control.Monad.Trans.Except (ExceptT(..), runExceptT)-import Control.Monad.Trans.State.Strict (StateT, evalStateT)-import Control.Monad.Trans.Reader (ReaderT, runReaderT)--import qualified Language.PureScript as P-import qualified Language.PureScript.Bundle as Bundle-import Language.PureScript.Interactive--import Network.HTTP.Types.Header (hContentType, hCacheControl,- hPragma, hExpires)-import Network.HTTP.Types.Status (status200, status404, status503)-import qualified Network.Wai as Wai-import qualified Network.Wai.Handler.Warp as Warp-import qualified Network.Wai.Handler.WebSockets as WS-import qualified Network.WebSockets as WS--import qualified Options.Applicative as Opts--import qualified Paths_purescript as Paths--import System.Console.Haskeline-import System.IO.UTF8 (readUTF8File)-import System.Exit-import System.FilePath ((</>))-import System.FilePath.Glob (glob)-import System.Process (readProcessWithExitCode)---- | Command line options-data PSCiOptions = PSCiOptions- { psciInputFile :: [FilePath]- , psciBackend :: Backend- }--inputFile :: Opts.Parser FilePath-inputFile = Opts.strArgument $- Opts.metavar "FILE"- <> Opts.help "Optional .purs files to load on start"--nodePathOption :: Opts.Parser (Maybe FilePath)-nodePathOption = Opts.optional . Opts.strOption $- Opts.metavar "FILE"- <> Opts.long "node-path"- <> Opts.help "Path to the Node executable"--nodeFlagsOption :: Opts.Parser [String]-nodeFlagsOption = Opts.option parser $- Opts.long "node-opts"- <> Opts.metavar "OPTS"- <> Opts.value []- <> Opts.help "Flags to pass to node, separated by spaces"- where- parser = words <$> Opts.str--port :: Opts.Parser Int-port = Opts.option Opts.auto $- Opts.long "port"- <> Opts.short 'p'- <> Opts.help "The web server port"--backend :: Opts.Parser Backend-backend =- (browserBackend <$> port)- <|> (nodeBackend <$> nodePathOption <*> nodeFlagsOption)--psciOptions :: Opts.Parser PSCiOptions-psciOptions = PSCiOptions <$> many inputFile- <*> backend--version :: Opts.Parser (a -> a)-version = Opts.abortOption (Opts.InfoMsg (showVersion Paths.version)) $- Opts.long "version" <>- Opts.help "Show the version number" <>- Opts.hidden--getOpt :: IO PSCiOptions-getOpt = Opts.execParser opts- where- opts = Opts.info (version <*> Opts.helper <*> psciOptions) infoModList- infoModList = Opts.fullDesc <> headerInfo <> footerInfo- headerInfo = Opts.header "psci - Interactive mode for PureScript"- footerInfo = Opts.footer $ "psci " ++ showVersion Paths.version---- | Parses the input and returns either a command, or an error as a 'String'.-getCommand :: forall m. MonadException m => InputT m (Either String (Maybe Command))-getCommand = handleInterrupt (return (Right Nothing)) $ do- line <- withInterrupt $ getInputLine "> "- case line of- Nothing -> return (Right (Just QuitPSCi)) -- Ctrl-D when input is empty- Just "" -> return (Right Nothing)- Just s -> return . fmap Just $ parseCommand s--pasteMode :: forall m. MonadException m => InputT m (Either String Command)-pasteMode =- parseCommand <$> go []- where- go :: [String] -> InputT m String- go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine "… "---- | Make a JavaScript bundle for the browser.-bundle :: IO (Either Bundle.ErrorMessage String)-bundle = runExceptT $ do- inputFiles <- liftIO (glob (".psci_modules" </> "node_modules" </> "*" </> "*.js"))- input <- for inputFiles $ \filename -> do- js <- liftIO (readUTF8File filename)- mid <- Bundle.guessModuleIdentifier filename- length js `seq` return (mid, js)- Bundle.bundle input [] Nothing "PSCI"--indexJS :: IsString string => string-indexJS = $(embedStringFile "psci/static/index.js")--indexPage :: IsString string => string-indexPage = $(embedStringFile "psci/static/index.html")---- | All of the functions required to implement a PSCi backend-data Backend = forall state. Backend- { _backendSetup :: IO state- -- ^ Initialize, and call the continuation when the backend is ready- , _backendEval :: state -> String -> IO ()- -- ^ Evaluate JavaScript code- , _backendReload :: state -> IO ()- -- ^ Reload the compiled code- , _backendShutdown :: state -> IO ()- -- ^ Shut down the backend- }---- | Commands which can be sent to the browser-data BrowserCommand- = Eval (MVar String)- -- ^ Evaluate the latest JS- | Reload- -- ^ Reload the page---- | State for the browser backend-data BrowserState = BrowserState- { browserCommands :: TChan BrowserCommand- -- ^ A channel which receives data when the compiled JS has- -- been updated- , browserShutdownNotice :: MVar ()- -- ^ An MVar which becomes full when the server should shut down- , browserIndexJS :: TVar (Maybe String)- -- ^ A TVar holding the latest compiled JS- , browserBundleJS :: TVar (Maybe String)- -- ^ A TVar holding the latest bundled JS- }--browserBackend :: Int -> Backend-browserBackend serverPort = Backend setup evaluate reload shutdown- where- setup :: IO BrowserState- setup = do- shutdownVar <- newEmptyMVar- cmdChan <- newBroadcastTChanIO- indexJs <- newTVarIO Nothing- bundleJs <- newTVarIO Nothing-- let- handleWebsocket :: WS.PendingConnection -> IO ()- handleWebsocket pending = do- conn <- WS.acceptRequest pending- -- Fork a thread to keep the connection alive- WS.forkPingThread conn 10- -- Clone the command channel- cmdChanCopy <- atomically $ dupTChan cmdChan- -- Listen for commands- forever $ do- cmd <- atomically $ readTChan cmdChanCopy- case cmd of- Eval resultVar -> void $ do- WS.sendTextData conn ("eval" :: Text)- result <- WS.receiveData conn- -- With many connected clients, all but one of- -- these attempts will fail.- tryPutMVar resultVar (unpack result)- Reload ->- WS.sendTextData conn ("reload" :: Text)-- shutdownHandler :: IO () -> IO ()- shutdownHandler stopServer = void . forkIO $ do- () <- takeMVar shutdownVar- stopServer-- onException :: Maybe Wai.Request -> SomeException -> IO ()- onException req ex- | Just (_ :: WS.ConnectionException) <- fromException ex- = return () -- ignore websocket disconnects- | otherwise = Warp.defaultOnException req ex-- staticServer :: Wai.Application- staticServer req respond =- case Wai.pathInfo req of- [] ->- respond $ Wai.responseLBS status200- [(hContentType, "text/html")]- indexPage- ["js", "index.js"] ->- respond $ Wai.responseLBS status200- [(hContentType, "application/javascript")]- indexJS- ["js", "latest.js"] -> do- may <- readTVarIO indexJs- case may of- Nothing ->- respond $ Wai.responseLBS status503 [] "Service not available"- Just js ->- respond $ Wai.responseLBS status200- [ (hContentType, "application/javascript")- , (hCacheControl, "no-cache, no-store, must-revalidate")- , (hPragma, "no-cache")- , (hExpires, "0")- ]- (fromString js)- ["js", "bundle.js"] -> do- may <- readTVarIO bundleJs- case may of- Nothing ->- respond $ Wai.responseLBS status503 [] "Service not available"- Just js ->- respond $ Wai.responseLBS status200- [ (hContentType, "application/javascript")]- (fromString js)- _ -> respond $ Wai.responseLBS status404 [] "Not found"-- let browserState = BrowserState cmdChan shutdownVar indexJs bundleJs- createBundle browserState-- putStrLn $ "Serving http://localhost:" <> show serverPort <> "/. Waiting for connections..."- _ <- forkIO $ Warp.runSettings ( Warp.setInstallShutdownHandler shutdownHandler- . Warp.setPort serverPort- . Warp.setOnException onException- $ Warp.defaultSettings- ) $- WS.websocketsOr WS.defaultConnectionOptions- handleWebsocket- staticServer- return browserState-- createBundle :: BrowserState -> IO ()- createBundle state = do- putStrLn "Bundling Javascript..."- ejs <- bundle- case ejs of- Left err -> do- putStrLn (unlines (Bundle.printErrorMessage err))- exitFailure- Right js ->- atomically $ writeTVar (browserBundleJS state) (Just js)-- reload :: BrowserState -> IO ()- reload state = do- createBundle state- atomically $ writeTChan (browserCommands state) Reload-- shutdown :: BrowserState -> IO ()- shutdown state = putMVar (browserShutdownNotice state) ()-- evaluate :: BrowserState -> String -> IO ()- evaluate state js = liftIO $ do- resultVar <- newEmptyMVar- atomically $ do- writeTVar (browserIndexJS state) (Just js)- writeTChan (browserCommands state) (Eval resultVar)- result <- takeMVar resultVar- putStrLn result--nodeBackend :: Maybe FilePath -> [String] -> Backend-nodeBackend nodePath nodeArgs = Backend setup eval reload shutdown- where- setup :: IO ()- setup = return ()-- eval :: () -> String -> IO ()- eval _ _ = do- writeFile indexFile "require('$PSCI')['$main']();"- process <- maybe findNodeProcess (pure . pure) nodePath- result <- traverse (\node -> readProcessWithExitCode node (nodeArgs ++ [indexFile]) "") process- case result of- Just (ExitSuccess, out, _) -> putStrLn out- Just (ExitFailure _, _, err) -> putStrLn err- Nothing -> putStrLn "Couldn't find node.js"-- reload :: () -> IO ()- reload _ = return ()-- shutdown :: () -> IO ()- shutdown _ = return ()---- | Get command line options and drop into the REPL-main :: IO ()-main = getOpt >>= loop- where- loop :: PSCiOptions -> IO ()- loop PSCiOptions{..} = do- inputFiles <- concat <$> traverse glob psciInputFile- e <- runExceptT $ do- modules <- ExceptT (loadAllModules inputFiles)- unless (supportModuleIsDefined (map snd modules)) . liftIO $ do- putStrLn supportModuleMessage- exitFailure- (externs, env) <- ExceptT . runMake . make $ modules- return (modules, externs, env)- case psciBackend of- Backend setup eval reload (shutdown :: state -> IO ()) ->- case e of- Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure- Right (modules, externs, env) -> do- historyFilename <- getHistoryFilename- let settings = defaultSettings { historyFile = Just historyFilename }- initialState = PSCiState [] [] (zip (map snd modules) externs)- config = PSCiConfig inputFiles env- runner = flip runReaderT config- . flip evalStateT initialState- . runInputT (setComplete completion settings)-- go :: state -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()- go state = do- c <- getCommand- case c of- Left err -> outputStrLn err >> go state- Right Nothing -> go state- Right (Just PasteLines) -> do- c' <- pasteMode- case c' of- Left err -> outputStrLn err >> go state- Right c'' -> handleCommandWithInterrupts state c''- Right (Just QuitPSCi) -> do- outputStrLn quitMessage- liftIO $ shutdown state- Right (Just c') -> handleCommandWithInterrupts state c'-- handleCommandWithInterrupts- :: state- -> Command- -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()- handleCommandWithInterrupts state cmd = do- handleInterrupt (outputStrLn "Interrupted.")- (withInterrupt (lift (handleCommand (liftIO . eval state) (liftIO (reload state)) cmd)))- go state-- putStrLn prologueMessage- setup >>= runner . go
− psci/static/index.html
@@ -1,10 +0,0 @@-<!DOCTYPE html>-<html>-<head>- <title>PureScript Interactive</title>- <script src='js/bundle.js'></script>- <script src='js/index.js'></script>-</head>-<body>-</body>-</html>
− psci/static/index.js
@@ -1,63 +0,0 @@-var get = function get(uri, callback, onError) {- var request = new XMLHttpRequest();- request.addEventListener('load', function() {- callback(request.responseText);- });- request.addEventListener('error', onError);- request.open('GET', uri);- request.send();-};-var evaluate = function evaluate(js) {- var buffer = [];- // Save the old console.log function- var oldLog = console.log;- console.log = function(s) {- // Push log output into a temporary buffer- // which will be returned to PSCi.- buffer.push(s);- };- // Replace any require(...) statements with lookups on the PSCI object.- var replaced = js.replace(/require\("[^"]*"\)/g, function(s) {- return "PSCI['" + s.substring(12, s.length - 2) + "']";- });- // Wrap the module and evaluate it.- var wrapped =- [ 'var module = {};'- , '(function(module) {'- , replaced- , '})(module);'- , 'return module.exports["$main"] && module.exports["$main"]();'- ].join('\n');- new Function(wrapped)();- // Restore console.log- console.log = oldLog;- return buffer.join('\n');-};-window.onload = function() {- var socket = new WebSocket('ws://localhost:' + location.port);- var evalNext = function reload() {- get('js/latest.js', function(response) {- try {- var result = evaluate(response);- socket.send(result);- } catch (ex) {- socket.send(ex.stack);- }- }, function(err) {- socket.send('Error sending JavaScript');- });- };- socket.onopen = function() {- console.log('Connected');- socket.onmessage = function(event) {- switch (event.data) {- case 'eval':- evalNext();- break;- case 'reload':- location.reload();- break;- }- };- };-};
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.10.7+version: 0.11.0 cabal-version: >=1.8 build-type: Simple license: BSD3@@ -8,7 +8,7 @@ maintainer: Phil Freeman <paf31@cantab.net> stability: experimental synopsis: PureScript Programming Language Compiler-description: A small strongly, statically typed programming language with expressive types, inspired by Haskell and compiling to Javascript.+description: A small strongly, statically typed programming language with expressive types, inspired by Haskell and compiling to JavaScript. category: Language Homepage: http://www.purescript.org/ author: Phil Freeman <paf31@cantab.net>,@@ -23,6 +23,7 @@ , examples/passing/*.js , examples/passing/2018/*.purs , examples/passing/2138/*.purs+ , examples/passing/2609/*.purs , examples/passing/ClassRefSyntax/*.purs , examples/passing/DctorOperatorAlias/*.purs , examples/passing/ExplicitImportReExport/*.purs@@ -92,8 +93,10 @@ , examples/docs/bower_components/purescript-prelude/src/*.purs , examples/docs/bower.json , examples/docs/src/*.purs- , psci/static/index.html- , psci/static/index.js+ , examples/docs/resolutions.json+ , app/static/index.html+ , app/static/index.js+ , app/static/*.css , tests/support/package.json , tests/support/bower.json , tests/support/setup-win.cmd@@ -101,6 +104,7 @@ , tests/support/pscide/src/*.purs , tests/support/pscide/src/*.js , tests/support/pscide/src/*.fail+ , tests/support/prelude-resolutions.json , stack.yaml , README.md , INSTALL.md@@ -111,9 +115,14 @@ type: git location: https://github.com/purescript/purescript.git +flag release+ description: Mark this build as a release build: prevents inclusion of extra+ info e.g. commit SHA in --version output)+ default: False+ library build-depends: base >=4.8 && <5,- aeson >= 0.8 && < 1.0,+ aeson >= 0.8 && < 1.1, aeson-better-errors >= 0.8, ansi-terminal >= 0.6.2 && < 0.7, base-compat >=0.6.0,@@ -133,7 +142,7 @@ fsnotify >= 0.2.1, Glob >= 0.7 && < 0.8, haskeline >= 0.7.0.0,- http-client >= 0.4.30 && <0.5,+ http-client >= 0.4.30 && < 0.6.0, http-types -any, language-javascript >= 0.6.0.9 && < 0.7, lens == 4.*,@@ -144,7 +153,7 @@ parallel >= 3.2 && < 3.3, parsec >=3.1.10, pattern-arrows >= 0.0.2 && < 0.1,- pipes >= 4.0.0 && < 4.3.0,+ pipes >= 4.0.0 && < 4.4.0, pipes-http -any, process >= 1.2.0 && < 1.5, protolude >= 0.1.6,@@ -180,15 +189,8 @@ Language.PureScript.Externs Language.PureScript.CodeGen Language.PureScript.CodeGen.JS- Language.PureScript.CodeGen.JS.AST Language.PureScript.CodeGen.JS.Common- Language.PureScript.CodeGen.JS.Optimizer- Language.PureScript.CodeGen.JS.Optimizer.Blocks- Language.PureScript.CodeGen.JS.Optimizer.Common- Language.PureScript.CodeGen.JS.Optimizer.Inliner- Language.PureScript.CodeGen.JS.Optimizer.MagicDo- Language.PureScript.CodeGen.JS.Optimizer.TCO- Language.PureScript.CodeGen.JS.Optimizer.Unused+ Language.PureScript.CodeGen.JS.Printer Language.PureScript.Constants Language.PureScript.CoreFn Language.PureScript.CoreFn.Ann@@ -199,6 +201,15 @@ Language.PureScript.CoreFn.Module Language.PureScript.CoreFn.Traversals Language.PureScript.CoreFn.ToJSON+ Language.PureScript.CoreImp+ Language.PureScript.CoreImp.AST+ Language.PureScript.CoreImp.Optimizer+ Language.PureScript.CoreImp.Optimizer.Blocks+ Language.PureScript.CoreImp.Optimizer.Common+ Language.PureScript.CoreImp.Optimizer.Inliner+ Language.PureScript.CoreImp.Optimizer.MagicDo+ Language.PureScript.CoreImp.Optimizer.TCO+ Language.PureScript.CoreImp.Optimizer.Unused Language.PureScript.Comments Language.PureScript.Environment Language.PureScript.Errors@@ -221,7 +232,6 @@ Language.PureScript.Parser.Types Language.PureScript.Pretty Language.PureScript.Pretty.Common- Language.PureScript.Pretty.JS Language.PureScript.Pretty.Kinds Language.PureScript.Pretty.Types Language.PureScript.Pretty.Values@@ -231,6 +241,7 @@ Language.PureScript.Sugar.BindingGroups Language.PureScript.Sugar.CaseDeclarations Language.PureScript.Sugar.DoNotation+ Language.PureScript.Sugar.LetPattern Language.PureScript.Sugar.Names Language.PureScript.Sugar.Names.Common Language.PureScript.Sugar.Names.Env@@ -250,7 +261,6 @@ Language.PureScript.TypeChecker.Entailment Language.PureScript.TypeChecker.Kinds Language.PureScript.TypeChecker.Monad- Language.PureScript.TypeChecker.Rows Language.PureScript.TypeChecker.Skolems Language.PureScript.TypeChecker.Subsumption Language.PureScript.TypeChecker.Synonyms@@ -339,191 +349,64 @@ other-modules: Paths_purescript ghc-options: -Wall -O2 -executable psc+executable purs build-depends: base >=4 && <5,- purescript -any,- aeson >= 0.8 && < 1.0,+ aeson >= 0.8 && < 1.1, ansi-terminal >= 0.6.2 && < 0.7,- base-compat >=0.6.0,- bytestring -any,- containers -any,- directory -any,- filepath -any,- Glob >= 0.7 && < 0.8,- mtl -any,- optparse-applicative >= 0.13.0,- parsec -any,- text -any,- time -any,- transformers -any,- transformers-compat -any,- utf8-string >= 1 && < 2- main-is: Main.hs- buildable: True- hs-source-dirs: psc- other-modules: Paths_purescript- ghc-options: -Wall -O2 -fno-warn-unused-do-bind -threaded -rtsopts "-with-rtsopts=-N"--executable psci- build-depends: base >=4 && <5,- purescript -any,+ ansi-wl-pprint -any, base-compat >=0.6.0,+ blaze-html -any, boxes >= 0.1.4 && < 0.2.0, bytestring -any, containers -any, directory -any,- filepath -any, file-embed -any,- Glob -any,+ filepath -any,+ Glob >= 0.7 && < 0.8, haskeline >= 0.7.0.0, http-types == 0.9.*,+ monad-logger -any, mtl -any,+ network -any, optparse-applicative >= 0.13.0, parsec -any, process -any,+ protolude >= 0.1.6,+ purescript -any,+ sourcemap >= 0.1.6,+ split -any, stm >= 0.2.4.0, text -any, time -any, transformers -any, transformers-compat -any,+ utf8-string >= 1 && < 2, wai == 3.*, wai-websockets == 3.*, warp == 3.*,- websockets >= 0.9 && <0.10+ websockets >= 0.9 && <0.11 main-is: Main.hs buildable: True- hs-source-dirs: psci- other-modules: Paths_purescript- ghc-options: -Wall -O2--executable psc-docs- build-depends: base >=4 && <5,- purescript -any,- ansi-wl-pprint -any,- directory -any,- filepath -any,- Glob -any,- mtl -any,- optparse-applicative >= 0.13.0,- process -any,- split -any,- text -any,- transformers -any,- transformers-compat -any- main-is: Main.hs- other-modules: Paths_purescript- buildable: True- hs-source-dirs: psc-docs- other-modules: Ctags- Etags- Tags- ghc-options: -Wall -O2--executable psc-publish- build-depends: base >=4 && <5,- purescript -any,- aeson >= 0.8 && < 1.0,- bytestring -any,- optparse-applicative -any,- time -any,- transformers -any- main-is: Main.hs- other-modules: Paths_purescript- buildable: True- hs-source-dirs: psc-publish- ghc-options: -Wall -O2--executable psc-package- build-depends: base >=4 && <5,- purescript -any,- aeson -any,- aeson-pretty -any,- bytestring -any,- containers -any,- foldl -any,- optparse-applicative -any,- system-filepath -any,- text -any,- turtle ==1.3.*- main-is: Main.hs- other-modules: Paths_purescript- buildable: True- hs-source-dirs: psc-package- ghc-options: -Wall -O2--executable psc-hierarchy- build-depends: base >=4 && <5,- purescript -any,- directory -any,- filepath -any,- Glob -any,- mtl -any,- optparse-applicative >= 0.13.0,- parsec -any,- process -any,- text -any- main-is: Main.hs+ hs-source-dirs: app other-modules: Paths_purescript- buildable: True- hs-source-dirs: hierarchy- other-modules:- ghc-options: -Wall -O2--executable psc-bundle- main-is: Main.hs- other-modules: Paths_purescript- other-extensions:- build-depends: base >=4 && <5,- bytestring -any,- purescript -any,- directory -any,- aeson >= 0.8 && < 1.0,- filepath -any,- Glob -any,- mtl -any,- optparse-applicative >= 0.13.0,- sourcemap >= 0.1.6,- transformers -any,- transformers-compat -any,- utf8-string >= 1 && < 2-- ghc-options: -Wall -O2- hs-source-dirs: psc-bundle--executable psc-ide-server- main-is: Main.hs- other-modules: Paths_purescript- other-extensions:- build-depends: base >=4 && <5,- aeson >= 0.8 && < 1.0,- bytestring -any,- purescript -any,- directory -any,- filepath -any,- monad-logger -any,- mtl -any,- network -any,- optparse-applicative >= 0.13.0,- protolude >= 0.1.6,- stm -any,- text -any,- transformers -any- ghc-options: -Wall -O2 -threaded- hs-source-dirs: psc-ide-server+ Command.Bundle+ Command.Compile+ Command.Docs+ Command.Docs.Ctags+ Command.Docs.Etags+ Command.Docs.Tags+ Command.Docs.Html+ Command.Hierarchy+ Command.Ide+ Command.Publish+ Command.REPL+ Version+ ghc-options: -Wall -O2 -fno-warn-unused-do-bind -threaded -rtsopts "-with-rtsopts=-N" -executable psc-ide-client- main-is: Main.hs- other-modules: Paths_purescript- other-extensions:- build-depends: base >=4 && <5,- base-compat >=0.6.0,- bytestring -any,- mtl -any,- network -any,- optparse-applicative >= 0.13.0,- text -any- ghc-options: -Wall -O2- hs-source-dirs: psc-ide-client+ if flag(release)+ cpp-options: -DRELEASE+ else+ build-depends: gitrev >= 1.2.0 && <1.3 test-suite tests build-depends: base >=4 && <5,@@ -566,6 +449,9 @@ TestPrimDocs TestPscPublish TestPsci+ TestPsci.CommandTest+ TestPsci.CompletionTest+ TestPsci.TestEnv TestPscIde PscIdeSpec Language.PureScript.Ide.Test
src/Language/PureScript/AST/Binders.hs view
@@ -61,7 +61,7 @@ -- A binder with a type annotation -- | TypedBinder Type Binder- deriving (Show, Eq)+ deriving (Show, Eq, Ord) -- | -- Collect all names introduced in binders in an expression@@ -81,3 +81,11 @@ 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
@@ -38,14 +38,27 @@ data TypeSearch = TSBefore Environment -- ^ An Environment captured for later consumption by type directed search- | TSAfter [(Qualified Ident, Type)]+ | TSAfter+ { tsAfterIdentifiers :: [(Qualified Text, Type)]+ -- ^ The identifiers that fully satisfy the subsumption check+ , tsAfterRecordFields :: Maybe [(Label, Type)]+ -- ^ 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 :: (Type -> Type) -> TypeSearch -> TypeSearch+onTypeSearchTypes f = runIdentity . onTypeSearchTypesM (Identity . f)++onTypeSearchTypesM :: (Applicative m) => (Type -> m Type) -> TypeSearch -> m TypeSearch+onTypeSearchTypesM f (TSAfter i r) = TSAfter <$> traverse (traverse f) i <*> traverse (traverse (traverse f)) r+onTypeSearchTypesM _ (TSBefore env) = pure (TSBefore env)+ -- | A type of error messages data SimpleErrorMessage- = ModuleNotFound ModuleName + = ModuleNotFound ModuleName | ErrorParsingFFIModule FilePath (Maybe Bundle.ErrorMessage) | ErrorParsingModule P.ParseError | MissingFFIModule ModuleName@@ -83,7 +96,7 @@ | NameIsUndefined Ident | UndefinedTypeVariable (ProperName 'TypeName) | PartiallyAppliedSynonym (Qualified (ProperName 'TypeName))- | EscapedSkolem (Maybe Expr)+ | EscapedSkolem Text (Maybe SourceSpan) Type | TypesDoNotUnify Type Type | KindsDoNotUnify Kind Kind | ConstrainedTypeUnified Type Type@@ -93,6 +106,8 @@ | UnknownClass (Qualified (ProperName 'ClassName)) | PossiblyInfiniteInstance (Qualified (ProperName 'ClassName)) [Type] | CannotDerive (Qualified (ProperName 'ClassName)) [Type]+ | InvalidDerivedInstance (Qualified (ProperName 'ClassName)) [Type] Int+ | ExpectedTypeConstructor (Qualified (ProperName 'ClassName)) [Type] Type | InvalidNewtypeInstance (Qualified (ProperName 'ClassName)) [Type] | CannotFindDerivingType (ProperName 'TypeName) | DuplicateLabel Label (Maybe Expr)@@ -140,11 +155,14 @@ | CannotGeneralizeRecursiveFunction Ident Type | CannotDeriveNewtypeForData (ProperName 'TypeName) | ExpectedWildcard (ProperName 'TypeName)- | CannotUseBindWithDo+ | CannotUseBindWithDo Ident -- | instance name, type class, expected argument count, actual argument count | ClassInstanceArityMismatch Ident (Qualified (ProperName 'ClassName)) Int Int -- | a user-defined warning raised by using the Warn type class | UserDefinedWarning Type+ -- | a declaration couldn't be used because there wouldn't be enough information+ -- | to choose an instance+ | UnusableDeclaration Ident deriving (Show) -- | Error message hints, providing more detailed information about failure.@@ -388,8 +406,11 @@ -- | -- A value declaration (name, top-level binders, optional guard, value) --- | ValueDeclaration Ident NameKind [Binder] (Either [(Guard, Expr)] Expr)+ | ValueDeclaration Ident NameKind [Binder] [GuardedExpr] -- |+ -- A declaration paired with pattern matching in let-in expression (binder, optional guard, value)+ | BoundValueDeclaration Binder Expr+ -- | -- A minimal mutually recursive set of value declarations -- | BindingGroupDeclaration [(Ident, NameKind, Expr)]@@ -550,9 +571,20 @@ -- | -- A guard is just a boolean-valued expression that appears alongside a set of binders ---type Guard = Expr+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@@ -595,7 +627,7 @@ -- | -- Function introduction --- | Abs (Either Ident Binder) Expr+ | Abs Binder Expr -- | -- Function application --@@ -682,7 +714,7 @@ -- | -- The result expression or a collect of guarded expressions --- , caseAlternativeResult :: Either [(Guard, Expr)] Expr+ , caseAlternativeResult :: [GuardedExpr] } deriving (Show) -- |@@ -742,3 +774,11 @@ $(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''DeclarationRef) $(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ImportDeclarationType)++isTrueExpr :: Expr -> Bool+isTrueExpr (Literal (BooleanLiteral True)) = True+isTrueExpr (Var (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) = True+isTrueExpr (Var (Qualified (Just (ModuleName [ProperName "Data", ProperName "Boolean"])) (Ident "otherwise"))) = True+isTrueExpr (TypedValue _ e _) = isTrueExpr e+isTrueExpr (PositionedValue _ _ e) = isTrueExpr e+isTrueExpr _ = False
src/Language/PureScript/AST/Exported.hs view
@@ -108,7 +108,7 @@ -- 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 cs _) = concatMap fromConstraint cs+ go (ConstrainedType c _) = fromConstraint c go _ = [] typeInstanceConstituents (PositionedDeclaration _ _ d) = typeInstanceConstituents d
src/Language/PureScript/AST/Traversals.hs view
@@ -6,7 +6,6 @@ import Prelude.Compat import Control.Monad-import Control.Arrow ((***), (+++)) import Data.Foldable (fold) import Data.List (mapAccumL)@@ -21,6 +20,21 @@ import Language.PureScript.Traversals 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 (map f guards) (g rhs)+ everywhereOnValues :: (Declaration -> Declaration) -> (Expr -> Expr)@@ -33,7 +47,8 @@ where f' :: Declaration -> Declaration f' (DataBindingGroupDeclaration ds) = f (DataBindingGroupDeclaration (map f' ds))- f' (ValueDeclaration name nameKind bs val) = f (ValueDeclaration name nameKind (map h' bs) ((map (g' *** g') +++ g') val))+ f' (ValueDeclaration name nameKind bs val) = f (ValueDeclaration name nameKind (map h' bs) (map (mapGuardedExpr handleGuard g') val))+ f' (BoundValueDeclaration b expr) = f (BoundValueDeclaration (h' b) (g' expr)) f' (BindingGroupDeclaration ds) = f (BindingGroupDeclaration (map (\(name, nameKind, val) -> (name, nameKind, g' val)) ds)) f' (TypeClassDeclaration name args implies deps ds) = f (TypeClassDeclaration name args implies deps (map f' ds)) f' (TypeInstanceDeclaration name cs className args ds) = f (TypeInstanceDeclaration name cs className args (mapTypeInstanceBody (map f') ds))@@ -49,7 +64,7 @@ g' (Accessor prop v) = g (Accessor prop (g' v)) g' (ObjectUpdate obj vs) = g (ObjectUpdate (g' obj) (map (fmap g') vs)) g' (ObjectUpdateNested obj vs) = g (ObjectUpdateNested (g' obj) (fmap g' vs))- g' (Abs name v) = g (Abs name (g' v))+ g' (Abs binder v) = g (Abs (h' binder) (g' v)) g' (App v1 v2) = g (App (g' v1) (g' v2)) g' (IfThenElse v1 v2 v3) = g (IfThenElse (g' v1) (g' v2) (g' v3)) g' (Case vs alts) = g (Case (map g' vs) (map handleCaseAlternative alts))@@ -77,7 +92,7 @@ handleCaseAlternative :: CaseAlternative -> CaseAlternative handleCaseAlternative ca = ca { caseAlternativeBinders = map h' (caseAlternativeBinders ca)- , caseAlternativeResult = (map (g' *** g') +++ g') (caseAlternativeResult ca)+ , caseAlternativeResult = map (mapGuardedExpr handleGuard g') (caseAlternativeResult ca) } handleDoNotationElement :: DoNotationElement -> DoNotationElement@@ -86,6 +101,10 @@ handleDoNotationElement (DoNotationLet ds) = DoNotationLet (map 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)@@ -101,10 +120,11 @@ f' :: Declaration -> m Declaration f' (DataBindingGroupDeclaration ds) = DataBindingGroupDeclaration <$> traverse (f' <=< f) ds- f' (ValueDeclaration name nameKind bs val) = ValueDeclaration name nameKind <$> traverse (h' <=< h) bs <*> eitherM (traverse (pairM (g' <=< g) (g' <=< g))) (g' <=< g) val+ f' (ValueDeclaration name nameKind bs val) = ValueDeclaration 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 name args implies deps ds) = TypeClassDeclaration name args implies deps <$> traverse (f' <=< f) ds f' (TypeInstanceDeclaration name cs className args ds) = TypeInstanceDeclaration name cs className args <$> traverseTypeInstanceBody (traverse (f' <=< f)) ds+ f' (BoundValueDeclaration b expr) = BoundValueDeclaration <$> h' b <*> g' expr f' (PositionedDeclaration pos com d) = PositionedDeclaration pos com <$> (f d >>= f') f' other = f other @@ -117,7 +137,7 @@ 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 name v) = Abs name <$> (g v >>= g')+ g' (Abs binder v) = Abs <$> (h binder >>= h') <*> (g v >>= g') g' (App v1 v2) = App <$> (g v1 >>= g') <*> (g v2 >>= 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@@ -146,7 +166,7 @@ handleCaseAlternative (CaseAlternative bs val) = CaseAlternative <$> traverse (h' <=< h) bs- <*> eitherM (traverse (pairM (g' <=< g) (g' <=< g))) (g' <=< g) val+ <*> traverse (guardedExprM handleGuard (g' <=< g)) val handleDoNotationElement :: DoNotationElement -> m DoNotationElement handleDoNotationElement (DoNotationValue v) = DoNotationValue <$> (g' <=< g) v@@ -154,6 +174,10 @@ 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)@@ -169,8 +193,9 @@ f' :: Declaration -> m Declaration f' (DataBindingGroupDeclaration ds) = (DataBindingGroupDeclaration <$> traverse f' ds) >>= f- f' (ValueDeclaration name nameKind bs val) = (ValueDeclaration name nameKind <$> traverse h' bs <*> eitherM (traverse (pairM g' g')) g' val) >>= f+ f' (ValueDeclaration name nameKind bs val) = (ValueDeclaration 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 b expr) = (BoundValueDeclaration <$> h' b <*> g' expr) >>= f f' (TypeClassDeclaration name args implies deps ds) = (TypeClassDeclaration name args implies deps <$> traverse f' ds) >>= f f' (TypeInstanceDeclaration name cs className args ds) = (TypeInstanceDeclaration name cs className args <$> traverseTypeInstanceBody (traverse f') ds) >>= f f' (PositionedDeclaration pos com d) = (PositionedDeclaration pos com <$> f' d) >>= f@@ -185,7 +210,7 @@ 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 name v) = (Abs name <$> g' v) >>= g+ g' (Abs binder v) = (Abs <$> h' binder <*> g' v) >>= g g' (App v1 v2) = (App <$> g' v1 <*> g' v2) >>= 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@@ -214,7 +239,7 @@ handleCaseAlternative (CaseAlternative bs val) = CaseAlternative <$> traverse h' bs- <*> eitherM (traverse (pairM g' g')) g' val+ <*> traverse (guardedExprM handleGuard g') val handleDoNotationElement :: DoNotationElement -> m DoNotationElement handleDoNotationElement (DoNotationValue v) = DoNotationValue <$> g' v@@ -222,6 +247,10 @@ 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)@@ -241,11 +270,11 @@ f' :: Declaration -> r f' d@(DataBindingGroupDeclaration ds) = foldl (<>) (f d) (map f' ds)- f' d@(ValueDeclaration _ _ bs (Right val)) = foldl (<>) (f d) (map h' bs) <> g' val- f' d@(ValueDeclaration _ _ bs (Left gs)) = foldl (<>) (f d) (map h' bs ++ concatMap (\(grd, val) -> [g' grd, g' val]) gs)+ f' d@(ValueDeclaration _ _ bs val) = foldl (<>) (f d) (map h' bs ++ concatMap (\(GuardedExpr grd v) -> map k' grd ++ [g' v]) val) f' d@(BindingGroupDeclaration ds) = foldl (<>) (f d) (map (\(_, _, val) -> g' val) ds) f' d@(TypeClassDeclaration _ _ _ _ ds) = foldl (<>) (f d) (map f' ds) f' d@(TypeInstanceDeclaration _ _ _ _ (ExplicitInstance ds)) = foldl (<>) (f d) (map f' ds)+ f' d@(BoundValueDeclaration b expr) = f d <> h' b <> g' expr f' d@(PositionedDeclaration _ _ d1) = f d <> f' d1 f' d = f d @@ -258,7 +287,7 @@ g' v@(Accessor _ v1) = g v <> g' v1 g' v@(ObjectUpdate obj vs) = foldl (<>) (g v <> g' obj) (map (g' . snd) vs) g' v@(ObjectUpdateNested obj vs) = foldl (<>) (g v <> g' obj) (fmap g' vs)- g' v@(Abs _ v1) = g v <> g' v1+ g' v@(Abs b v1) = g v <> h' b <> g' v1 g' v@(App v1 v2) = g v <> g' v1 <> g' v2 g' v@(IfThenElse v1 v2 v3) = g v <> g' v1 <> g' v2 <> g' v3 g' v@(Case vs alts) = foldl (<>) (foldl (<>) (g v) (map g' vs)) (map i' alts)@@ -284,8 +313,8 @@ lit r _ _ = r i' :: CaseAlternative -> r- i' ca@(CaseAlternative bs (Right val)) = foldl (<>) (i ca) (map h' bs) <> g' val- i' ca@(CaseAlternative bs (Left gs)) = foldl (<>) (i ca) (map h' bs ++ concatMap (\(grd, val) -> [g' grd, g' val]) gs)+ i' ca@(CaseAlternative bs gs) =+ foldl (<>) (i ca) (map h' bs ++ concatMap (\(GuardedExpr grd val) -> map k' grd ++ [g' val]) gs) j' :: DoNotationElement -> r j' e@(DoNotationValue v) = j e <> g' v@@ -293,6 +322,10 @@ j' e@(DoNotationLet ds) = foldl (<>) (j e) (map 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@@ -316,8 +349,7 @@ f' :: s -> Declaration -> r f' s (DataBindingGroupDeclaration ds) = foldl (<>) r0 (map (f'' s) ds)- f' s (ValueDeclaration _ _ bs (Right val)) = foldl (<>) r0 (map (h'' s) bs) <> g'' s val- f' s (ValueDeclaration _ _ bs (Left gs)) = foldl (<>) r0 (map (h'' s) bs ++ concatMap (\(grd, val) -> [g'' s grd, g'' s val]) gs)+ f' s (ValueDeclaration _ _ bs val) = foldl (<>) r0 (map (h'' s) bs ++ concatMap (\(GuardedExpr grd v) -> map (k' s) grd ++ [g'' s v]) val) f' s (BindingGroupDeclaration ds) = foldl (<>) r0 (map (\(_, _, val) -> g'' s val) ds) f' s (TypeClassDeclaration _ _ _ _ ds) = foldl (<>) r0 (map (f'' s) ds) f' s (TypeInstanceDeclaration _ _ _ _ (ExplicitInstance ds)) = foldl (<>) r0 (map (f'' s) ds)@@ -336,7 +368,7 @@ g' s (Accessor _ v1) = g'' s v1 g' s (ObjectUpdate obj vs) = foldl (<>) (g'' s obj) (map (g'' s . snd) vs) g' s (ObjectUpdateNested obj vs) = foldl (<>) (g'' s obj) (fmap (g'' s) vs)- g' s (Abs _ v1) = g'' s v1+ g' s (Abs binder v1) = h'' s binder <> g'' s v1 g' s (App v1 v2) = g'' s v1 <> g'' s v2 g' s (IfThenElse v1 v2 v3) = g'' s v1 <> g'' s v2 <> g'' s v3 g' s (Case vs alts) = foldl (<>) (foldl (<>) r0 (map (g'' s) vs)) (map (i'' s) alts)@@ -368,8 +400,7 @@ i'' s ca = let (s', r) = i s ca in r <> i' s' ca i' :: s -> CaseAlternative -> r- i' s (CaseAlternative bs (Right val)) = foldl (<>) r0 (map (h'' s) bs) <> g'' s val- i' s (CaseAlternative bs (Left gs)) = foldl (<>) r0 (map (h'' s) bs ++ concatMap (\(grd, val) -> [g'' s grd, g'' s val]) gs)+ i' s (CaseAlternative bs gs) = foldl (<>) r0 (map (h'' s) bs ++ concatMap (\(GuardedExpr grd val) -> map (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@@ -380,6 +411,10 @@ j' s (DoNotationLet ds) = foldl (<>) r0 (map (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)@@ -393,13 +428,14 @@ , Expr -> m Expr , Binder -> m Binder , CaseAlternative -> m CaseAlternative- , DoNotationElement -> m DoNotationElement)+ , 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 (ValueDeclaration name nameKind bs val) = ValueDeclaration name nameKind <$> traverse (h'' s) bs <*> eitherM (traverse (pairM (g'' s) (g'' s))) (g'' s) val+ f' s (ValueDeclaration name nameKind bs val) = ValueDeclaration 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 name args implies deps ds) = TypeClassDeclaration name args implies deps <$> traverse (f'' s) ds f' s (TypeInstanceDeclaration name cs className args ds) = TypeInstanceDeclaration name cs className args <$> traverseTypeInstanceBody (traverse (f'' s)) ds@@ -416,7 +452,7 @@ 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 name v) = Abs name <$> g'' s v+ 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 (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@@ -444,7 +480,7 @@ i'' s = uncurry i' <=< i s - i' s (CaseAlternative bs val) = CaseAlternative <$> traverse (h'' s) bs <*> eitherM (traverse (pairM (g'' s) (g'' s))) (g'' s) val+ i' s (CaseAlternative bs val) = CaseAlternative <$> traverse (h'' s) bs <*> traverse (guardedExprM (k' s) (g'' s)) val j'' s = uncurry j' <=< j s @@ -453,6 +489,9 @@ 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+ everythingWithScope :: forall r . (Monoid r)@@ -479,14 +518,10 @@ f' s (DataBindingGroupDeclaration ds) = let s' = S.union s (S.fromList (mapMaybe getDeclIdent ds)) in foldMap (f'' s') ds- f' s (ValueDeclaration name _ bs (Right val)) =- let s' = S.insert name s- s'' = S.union s' (S.fromList (concatMap binderNames bs))- in foldMap (h'' s') bs <> g'' s'' val- f' s (ValueDeclaration name _ bs (Left gs)) =+ f' s (ValueDeclaration name _ bs val) = let s' = S.insert name s s'' = S.union s' (S.fromList (concatMap binderNames bs))- in foldMap (h'' s') bs <> foldMap (\(grd, val) -> g'' s'' grd <> g'' s'' val) gs+ in foldMap (h'' s') bs <> foldMap (l' s'') val f' s (BindingGroupDeclaration ds) = let s' = S.union s (S.fromList (map (\(name, _, _) -> name) ds)) in foldMap (\(_, _, val) -> g'' s' val) ds@@ -507,12 +542,9 @@ 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 (Left name) v1) =- let s' = S.insert name s- in g'' s' v1- g' s (Abs (Right b) v1) =+ g' s (Abs b v1) = let s' = S.union (S.fromList (binderNames b)) s- in g'' s' v1+ in h'' s b <> g'' s' v1 g' s (App v1 v2) = g'' s v1 <> g'' s v2 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@@ -546,12 +578,9 @@ i'' s a = i s a <> i' s a i' :: S.Set Ident -> CaseAlternative -> r- i' s (CaseAlternative bs (Right val)) =- let s' = S.union s (S.fromList (concatMap binderNames bs))- in foldMap (h'' s) bs <> g'' s' val- i' s (CaseAlternative bs (Left gs)) =+ i' s (CaseAlternative bs gs) = let s' = S.union s (S.fromList (concatMap binderNames bs))- in foldMap (h'' s) bs <> foldMap (\(grd, val) -> g'' s' grd <> g'' s' val) gs+ in foldMap (h'' s) bs <> foldMap (l' s') gs j'' :: S.Set Ident -> DoNotationElement -> (S.Set Ident, r) j'' s a = let (s', r) = j' s a in (s', j s a <> r)@@ -566,6 +595,17 @@ in (s', foldMap (f'' s') ds) j' s (PositionedDoNotationElement _ _ e1) = j'' s e1 + k' :: S.Set Ident -> Guard -> (S.Set Ident, r)+ k' s (ConditionGuard e) = (s, g'' s e)+ k' s (PatternGuard b e) =+ let s' = S.union (S.fromList (binderNames 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 (PositionedDeclaration _ _ d) = getDeclIdent d getDeclIdent (ValueDeclaration ident _ _ _) = Just ident@@ -642,4 +682,3 @@ g (TypedValue checkTy val t) = TypedValue checkTy val (f t) g (TypeClassDictionary c sco hints) = TypeClassDictionary (mapConstraintArgs (map f) c) sco hints g other = other-
src/Language/PureScript/Bundle.hs view
@@ -3,7 +3,7 @@ -- -- This module takes as input the individual generated modules from 'Language.PureScript.Make' and -- performs dead code elimination, filters empty modules,--- and generates the final Javascript bundle.+-- and generates the final JavaScript bundle. module Language.PureScript.Bundle ( bundle , bundleSM@@ -17,6 +17,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad import Control.Monad.Error.Class@@ -25,7 +26,7 @@ import Data.Char (chr, digitToInt) import Data.Generics (everything, everywhere, mkQ, mkT) import Data.Graph-import Data.List (nub, stripPrefix)+import Data.List (stripPrefix) import Data.Maybe (mapMaybe, catMaybes) import Data.Version (showVersion) import qualified Data.Set as S@@ -113,8 +114,8 @@ printErrorMessage (UnsupportedModulePath s) = [ "A CommonJS module has an unsupported name (" ++ show s ++ ")." , "The following file names are supported:"- , " 1) index.js (psc native modules)"- , " 2) foreign.js (psc foreign modules)"+ , " 1) index.js (PureScript native modules)"+ , " 2) foreign.js (PureScript foreign modules)" ] printErrorMessage InvalidTopLevel = [ "Expected a list of source elements at the top level." ]@@ -184,10 +185,10 @@ -- | Calculate dependencies and add them to the current element. expandDeps :: ModuleElement -> ModuleElement- expandDeps (Member n f nm decl _) = Member n f nm decl (nub $ dependencies modulePath decl)+ expandDeps (Member n f nm decl _) = Member n f nm decl (ordNub $ dependencies modulePath decl) expandDeps (ExportsList exps) = ExportsList (map expand exps) where- expand (ty, nm, n1, _) = (ty, nm, n1, nub (dependencies modulePath n1))+ expand (ty, nm, n1, _) = (ty, nm, n1, ordNub (dependencies modulePath n1)) expandDeps other = other dependencies :: ModuleIdentifier -> JSExpression -> [(ModuleIdentifier, String)]@@ -249,7 +250,7 @@ trailingCommaList (JSCTLComma l _) = commaList l trailingCommaList (JSCTLNone l) = commaList l --- | Attempt to create a Module from a Javascript AST.+-- | Attempt to create a Module from a JavaScript AST. -- -- Each type of module element is matched using pattern guards, and everything else is bundled into the -- Other constructor.@@ -671,7 +672,7 @@ -- | The bundling function. -- This function performs dead code elimination, filters empty modules--- and generates and prints the final Javascript bundle.+-- and generates and prints the final JavaScript bundle. bundleSM :: (MonadError ErrorMessage m) => [(ModuleIdentifier, Maybe FilePath, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@. -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination@@ -700,7 +701,7 @@ -- | The bundling function. -- This function performs dead code elimination, filters empty modules--- and generates and prints the final Javascript bundle.+-- and generates and prints the final JavaScript bundle. bundle :: (MonadError ErrorMessage m) => [(ModuleIdentifier, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@. -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
src/Language/PureScript/CodeGen.hs view
@@ -1,7 +1,7 @@ -- | -- A collection of modules related to code generation: -- --- [@Language.PureScript.CodeGen.JS@] Code generator for Javascript +-- [@Language.PureScript.CodeGen.JS@] Code generator for JavaScript -- module Language.PureScript.CodeGen (module C) where
src/Language/PureScript/CodeGen/JS.hs view
@@ -1,6 +1,5 @@--- |--- This module generates code in the simplified Javascript intermediate representation from Purescript code---+-- | This module generates code in the core imperative representation from+-- elaborated PureScript code. module Language.PureScript.CodeGen.JS ( module AST , module Common@@ -8,14 +7,15 @@ ) where import Prelude.Compat+import Protolude (ordNub) -import Control.Arrow ((&&&))+import Control.Arrow ((&&&), second) import Control.Monad (forM, replicateM, void) import Control.Monad.Except (MonadError, throwError) import Control.Monad.Reader (MonadReader, asks) import Control.Monad.Supply.Class -import Data.List ((\\), delete, intersect, nub)+import Data.List ((\\), delete, intersect) import qualified Data.Foldable as F import qualified Data.Map as M import Data.Maybe (fromMaybe, isNothing)@@ -25,9 +25,10 @@ import qualified Data.Text as T import Language.PureScript.AST.SourcePos-import Language.PureScript.CodeGen.JS.AST as AST import Language.PureScript.CodeGen.JS.Common as Common-import Language.PureScript.CodeGen.JS.Optimizer+import Language.PureScript.CoreImp.AST (AST, everywhereTopDownM, withSourceSpan)+import qualified Language.PureScript.CoreImp.AST as AST+import Language.PureScript.CoreImp.Optimizer import Language.PureScript.CoreFn import Language.PureScript.Crash import Language.PureScript.Errors (ErrorMessageHint(..), SimpleErrorMessage(..),@@ -41,49 +42,43 @@ import System.FilePath.Posix ((</>)) --- |--- Generate code in the simplified Javascript intermediate representation for all declarations in a+-- | Generate code in the simplified JavaScript intermediate representation for all declarations in a -- module.--- moduleToJs :: forall m . (Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m) => Module Ann- -> Maybe JS- -> m [JS]+ -> Maybe AST+ -> m [AST] moduleToJs (Module coms mn imps exps foreigns decls) foreign_ = rethrow (addHint (ErrorInModule mn)) $ do let usedNames = concatMap getNames decls let mnLookup = renameImports usedNames imps- jsImports <- traverse (importToJs mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ nub $ map snd imps+ jsImports <- traverse (importToJs mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ ordNub $ map snd imps let decls' = renameModules mnLookup decls jsDecls <- mapM bindToJs decls' optimized <- traverse (traverse optimize) jsDecls F.traverse_ (F.traverse_ checkIntegers) optimized comments <- not <$> asks optionsNoComments- let strict = JSStringLiteral Nothing "use strict"- let header = if comments && not (null coms) then JSComment Nothing coms strict else strict- let foreign' = [JSVariableIntroduction Nothing "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]+ let strict = AST.StringLiteral Nothing "use strict"+ let header = if comments && not (null coms) then AST.Comment Nothing coms strict else strict+ let foreign' = [AST.VariableIntroduction Nothing "$foreign" foreign_ | not $ null foreigns || isNothing foreign_] let moduleBody = header : foreign' ++ jsImports ++ concat optimized let foreignExps = exps `intersect` (fst `map` foreigns) let standardExps = exps \\ foreignExps- let exps' = JSObjectLiteral Nothing $ map (mkString . runIdent &&& JSVar Nothing . identToJs) standardExps+ let exps' = AST.ObjectLiteral Nothing $ map (mkString . runIdent &&& AST.Var Nothing . identToJs) standardExps ++ map (mkString . runIdent &&& foreignIdent) foreignExps- return $ moduleBody ++ [JSAssignment Nothing (accessorString "exports" (JSVar Nothing "module")) exps']+ return $ moduleBody ++ [AST.Assignment Nothing (accessorString "exports" (AST.Var Nothing "module")) exps'] where - -- |- -- Extracts all declaration names from a binding group.- --+ -- | Extracts all declaration names from a binding group. getNames :: Bind Ann -> [Ident] getNames (NonRec _ ident _) = [ident] getNames (Rec vals) = map (snd . fst) vals - -- |- -- Creates alternative names for each module to ensure they don't collide+ -- | Creates alternative names for each module to ensure they don't collide -- with declaration names.- -- renameImports :: [Ident] -> [(Ann, ModuleName)] -> M.Map ModuleName (Ann, ModuleName) renameImports = go M.empty where@@ -103,20 +98,16 @@ then freshModuleName (i + 1) mn' used else newName - -- |- -- Generates Javascript code for a module import, binding the required module+ -- | Generates JavaScript code for a module import, binding the required module -- to the alternative- --- importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS+ importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m AST importToJs mnLookup mn' = do let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup- let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn')))]- withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)+ let moduleBody = AST.App Nothing (AST.Var Nothing "require") [AST.StringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn')))]+ withPos ss $ AST.VariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody) - -- |- -- Replaces the `ModuleName`s in the AST so that the generated code refers to+ -- | Replaces the `ModuleName`s in the AST so that the generated code refers to -- the collision-avoiding renamed module imports.- -- renameModules :: M.Map ModuleName (Ann, ModuleName) -> [Bind Ann] -> [Bind Ann] renameModules mnLookup binds = let (f, _, _) = everywhereOnValues id goExpr goBinder@@ -135,29 +126,27 @@ renameQual q = q -- |- -- Generate code in the simplified Javascript intermediate representation for a declaration+ -- Generate code in the simplified JavaScript intermediate representation for a declaration --- bindToJs :: Bind Ann -> m [JS]+ bindToJs :: Bind Ann -> m [AST] bindToJs (NonRec ann ident val) = return <$> nonRecToJS ann ident val bindToJs (Rec vals) = forM vals (uncurry . uncurry $ nonRecToJS) - -- |- -- Generate code in the simplified Javascript intermediate representation for a single non-recursive+ -- | Generate code in the simplified JavaScript intermediate representation for a single non-recursive -- declaration. -- -- The main purpose of this function is to handle code generation for comments.- --- nonRecToJS :: Ann -> Ident -> Expr Ann -> m JS+ nonRecToJS :: Ann -> Ident -> Expr Ann -> m AST nonRecToJS a i e@(extractAnn -> (_, com, _, _)) | not (null com) = do withoutComment <- asks optionsNoComments if withoutComment then nonRecToJS a i (modifyAnn removeComments e)- else JSComment Nothing com <$> nonRecToJS a i (modifyAnn removeComments e)+ else AST.Comment Nothing com <$> nonRecToJS a i (modifyAnn removeComments e) nonRecToJS (ss, _, _, _) ident val = do js <- valueToJs val- withPos ss $ JSVariableIntroduction Nothing (identToJs ident) (Just js)+ withPos ss $ AST.VariableIntroduction Nothing (identToJs ident) (Just js) - withPos :: Maybe SourceSpan -> JS -> m JS+ withPos :: Maybe SourceSpan -> AST -> m AST withPos (Just ss) js = do withSM <- asks optionsSourceMaps return $ if withSM@@ -165,34 +154,28 @@ else js withPos Nothing js = return js - -- |- -- Generate code in the simplified Javascript intermediate representation for a variable based on a+ -- | Generate code in the simplified JavaScript intermediate representation for a variable based on a -- PureScript identifier.- --- var :: Ident -> JS- var = JSVar Nothing . identToJs+ var :: Ident -> AST+ var = AST.Var Nothing . identToJs - -- |- -- Generate code in the simplified Javascript intermediate representation for an accessor based on- -- a PureScript identifier. If the name is not valid in Javascript (symbol based, reserved name) an+ -- | Generate code in the simplified JavaScript intermediate representation for an accessor based on+ -- a PureScript identifier. If the name is not valid in JavaScript (symbol based, reserved name) an -- indexer is returned.- --- accessor :: Ident -> JS -> JS+ accessor :: Ident -> AST -> AST accessor (Ident prop) = accessorString $ mkString prop accessor (GenIdent _ _) = internalError "GenIdent in accessor" - accessorString :: PSString -> JS -> JS- accessorString prop = JSIndexer Nothing (JSStringLiteral Nothing prop)+ accessorString :: PSString -> AST -> AST+ accessorString prop = AST.Indexer Nothing (AST.StringLiteral Nothing prop) - -- |- -- Generate code in the simplified Javascript intermediate representation for a value or expression.- --- valueToJs :: Expr Ann -> m JS+ -- | Generate code in the simplified JavaScript intermediate representation for a value or expression.+ valueToJs :: Expr Ann -> m AST valueToJs e = let (ss, _, _, _) = extractAnn e in withPos ss =<< valueToJs' e - valueToJs' :: Expr Ann -> m JS+ valueToJs' :: Expr Ann -> m AST valueToJs' (Literal (pos, _, _, _) l) = maybe id rethrowWithPosition pos $ literalToValueJS l valueToJs' (Var (_, _, _, Just (IsConstructor _ [])) name) =@@ -207,27 +190,27 @@ extendObj obj sts valueToJs' e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) = let args = unAbs e- in return $ JSFunction Nothing Nothing (map identToJs args) (JSBlock Nothing $ map assign args)+ in return $ AST.Function Nothing Nothing (map identToJs args) (AST.Block Nothing $ map assign args) where unAbs :: Expr Ann -> [Ident] unAbs (Abs _ arg val) = arg : unAbs val unAbs _ = []- assign :: Ident -> JS- assign name = JSAssignment Nothing (accessorString (mkString $ runIdent name) (JSVar Nothing "this"))+ assign :: Ident -> AST+ assign name = AST.Assignment Nothing (accessorString (mkString $ runIdent name) (AST.Var Nothing "this")) (var name) valueToJs' (Abs _ arg val) = do ret <- valueToJs val- return $ JSFunction Nothing Nothing [identToJs arg] (JSBlock Nothing [JSReturn Nothing ret])+ return $ AST.Function Nothing Nothing [identToJs arg] (AST.Block Nothing [AST.Return Nothing ret]) valueToJs' e@App{} = do let (f, args) = unApp e [] args' <- mapM valueToJs args case f of Var (_, _, _, Just IsNewtype) _ -> return (head args') Var (_, _, _, Just (IsConstructor _ fields)) name | length args == length fields ->- return $ JSUnary Nothing JSNew $ JSApp Nothing (qualifiedToJS id name) args'+ return $ AST.Unary Nothing AST.New $ AST.App Nothing (qualifiedToJS id name) args' Var (_, _, _, Just IsTypeClassConstructor) name ->- return $ JSUnary Nothing JSNew $ JSApp Nothing (qualifiedToJS id name) args'- _ -> flip (foldl (\fn a -> JSApp Nothing fn [a])) args' <$> valueToJs f+ return $ AST.Unary Nothing AST.New $ AST.App Nothing (qualifiedToJS id name) args'+ _ -> flip (foldl (\fn a -> AST.App Nothing fn [a])) args' <$> valueToJs f where unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann]) unApp (App _ val arg) args = unApp val (arg : args)@@ -245,136 +228,142 @@ valueToJs' (Let _ ds val) = do ds' <- concat <$> mapM bindToJs ds ret <- valueToJs val- return $ JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing (ds' ++ [JSReturn Nothing ret]))) []+ return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (ds' ++ [AST.Return Nothing ret]))) [] valueToJs' (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =- return $ JSVariableIntroduction Nothing (properToJs ctor) (Just $- JSObjectLiteral Nothing [("create",- JSFunction Nothing Nothing ["value"]- (JSBlock Nothing [JSReturn Nothing $ JSVar Nothing "value"]))])+ return $ AST.VariableIntroduction Nothing (properToJs ctor) (Just $+ AST.ObjectLiteral Nothing [("create",+ AST.Function Nothing Nothing ["value"]+ (AST.Block Nothing [AST.Return Nothing $ AST.Var Nothing "value"]))]) valueToJs' (Constructor _ _ (ProperName ctor) []) =- return $ iife (properToJs ctor) [ JSFunction Nothing (Just (properToJs ctor)) [] (JSBlock Nothing [])- , JSAssignment Nothing (accessorString "value" (JSVar Nothing (properToJs ctor)))- (JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing (properToJs ctor)) []) ]+ return $ iife (properToJs ctor) [ AST.Function Nothing (Just (properToJs ctor)) [] (AST.Block Nothing [])+ , AST.Assignment Nothing (accessorString "value" (AST.Var Nothing (properToJs ctor)))+ (AST.Unary Nothing AST.New $ AST.App Nothing (AST.Var Nothing (properToJs ctor)) []) ] valueToJs' (Constructor _ _ (ProperName ctor) fields) = let constructor =- let body = [ JSAssignment Nothing ((accessorString $ mkString $ identToJs f) (JSVar Nothing "this")) (var f) | f <- fields ]- in JSFunction Nothing (Just (properToJs ctor)) (identToJs `map` fields) (JSBlock Nothing body)+ let body = [ AST.Assignment Nothing ((accessorString $ mkString $ identToJs f) (AST.Var Nothing "this")) (var f) | f <- fields ]+ in AST.Function Nothing (Just (properToJs ctor)) (identToJs `map` fields) (AST.Block Nothing body) createFn =- let body = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing (properToJs ctor)) (var `map` fields)- in foldr (\f inner -> JSFunction Nothing Nothing [identToJs f] (JSBlock Nothing [JSReturn Nothing inner])) body fields+ let body = AST.Unary Nothing AST.New $ AST.App Nothing (AST.Var Nothing (properToJs ctor)) (var `map` fields)+ in foldr (\f inner -> AST.Function Nothing Nothing [identToJs f] (AST.Block Nothing [AST.Return Nothing inner])) body fields in return $ iife (properToJs ctor) [ constructor- , JSAssignment Nothing (accessorString "create" (JSVar Nothing (properToJs ctor))) createFn+ , AST.Assignment Nothing (accessorString "create" (AST.Var Nothing (properToJs ctor))) createFn ] - iife :: Text -> [JS] -> JS- iife v exprs = JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing $ exprs ++ [JSReturn Nothing $ JSVar Nothing v])) []+ iife :: Text -> [AST] -> AST+ iife v exprs = AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing $ exprs ++ [AST.Return Nothing $ AST.Var Nothing v])) [] - literalToValueJS :: Literal (Expr Ann) -> m JS- literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)- literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)- literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s- literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing (fromString [c])- literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b- literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs- literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps+ literalToValueJS :: Literal (Expr Ann) -> m AST+ literalToValueJS (NumericLiteral (Left i)) = return $ AST.NumericLiteral Nothing (Left i)+ literalToValueJS (NumericLiteral (Right n)) = return $ AST.NumericLiteral Nothing (Right n)+ literalToValueJS (StringLiteral s) = return $ AST.StringLiteral Nothing s+ literalToValueJS (CharLiteral c) = return $ AST.StringLiteral Nothing (fromString [c])+ literalToValueJS (BooleanLiteral b) = return $ AST.BooleanLiteral Nothing b+ literalToValueJS (ArrayLiteral xs) = AST.ArrayLiteral Nothing <$> mapM valueToJs xs+ literalToValueJS (ObjectLiteral ps) = AST.ObjectLiteral Nothing <$> mapM (sndM valueToJs) ps - -- |- -- Shallow copy an object.- --- extendObj :: JS -> [(PSString, JS)] -> m JS+ -- | Shallow copy an object.+ extendObj :: AST -> [(PSString, AST)] -> m AST extendObj obj sts = do newObj <- freshName key <- freshName evaluatedObj <- freshName let- jsKey = JSVar Nothing key- jsNewObj = JSVar Nothing newObj- jsEvaluatedObj = JSVar Nothing evaluatedObj- block = JSBlock Nothing (evaluate:objAssign:copy:extend ++ [JSReturn Nothing jsNewObj])- evaluate = JSVariableIntroduction Nothing evaluatedObj (Just obj)- objAssign = JSVariableIntroduction Nothing newObj (Just $ JSObjectLiteral Nothing [])- copy = JSForIn Nothing key jsEvaluatedObj $ JSBlock Nothing [JSIfElse Nothing cond assign Nothing]- cond = JSApp Nothing (accessorString "call" (accessorString "hasOwnProperty" (JSObjectLiteral Nothing []))) [jsEvaluatedObj, jsKey]- assign = JSBlock Nothing [JSAssignment Nothing (JSIndexer Nothing jsKey jsNewObj) (JSIndexer Nothing jsKey jsEvaluatedObj)]- stToAssign (s, js) = JSAssignment Nothing (accessorString s jsNewObj) js+ jsKey = AST.Var Nothing key+ jsNewObj = AST.Var Nothing newObj+ jsEvaluatedObj = AST.Var Nothing evaluatedObj+ block = AST.Block Nothing (evaluate:objAssign:copy:extend ++ [AST.Return Nothing jsNewObj])+ evaluate = AST.VariableIntroduction Nothing evaluatedObj (Just obj)+ objAssign = AST.VariableIntroduction Nothing newObj (Just $ AST.ObjectLiteral Nothing [])+ copy = AST.ForIn Nothing key jsEvaluatedObj $ AST.Block Nothing [AST.IfElse Nothing cond assign Nothing]+ cond = AST.App Nothing (accessorString "call" (accessorString "hasOwnProperty" (AST.ObjectLiteral Nothing []))) [jsEvaluatedObj, jsKey]+ assign = AST.Block Nothing [AST.Assignment Nothing (AST.Indexer Nothing jsKey jsNewObj) (AST.Indexer Nothing jsKey jsEvaluatedObj)]+ stToAssign (s, js) = AST.Assignment Nothing (accessorString s jsNewObj) js extend = map stToAssign sts- return $ JSApp Nothing (JSFunction Nothing Nothing [] block) []+ return $ AST.App Nothing (AST.Function Nothing Nothing [] block) [] - -- |- -- Generate code in the simplified Javascript intermediate representation for a reference to a+ -- | Generate code in the simplified JavaScript intermediate representation for a reference to a -- variable.- --- varToJs :: Qualified Ident -> JS+ varToJs :: Qualified Ident -> AST varToJs (Qualified Nothing ident) = var ident varToJs qual = qualifiedToJS id qual - -- |- -- Generate code in the simplified Javascript intermediate representation for a reference to a+ -- | Generate code in the simplified JavaScript intermediate representation for a reference to a -- variable that may have a qualified name.- --- qualifiedToJS :: (a -> Ident) -> Qualified a -> JS- qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar Nothing . runIdent $ f a- qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar Nothing (moduleNameToJs mn'))- qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)+ qualifiedToJS :: (a -> Ident) -> Qualified a -> AST+ qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = AST.Var Nothing . runIdent $ f a+ qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (AST.Var Nothing (moduleNameToJs mn'))+ qualifiedToJS f (Qualified _ a) = AST.Var Nothing $ identToJs (f a) - foreignIdent :: Ident -> JS- foreignIdent ident = accessorString (mkString $ runIdent ident) (JSVar Nothing "$foreign")+ foreignIdent :: Ident -> AST+ foreignIdent ident = accessorString (mkString $ runIdent ident) (AST.Var Nothing "$foreign") - -- |- -- Generate code in the simplified Javascript intermediate representation for pattern match binders+ -- | Generate code in the simplified JavaScript intermediate representation for pattern match binders -- and guards.- --- bindersToJs :: Maybe SourceSpan -> [CaseAlternative Ann] -> [JS] -> m JS+ bindersToJs :: Maybe SourceSpan -> [CaseAlternative Ann] -> [AST] -> m AST bindersToJs maybeSpan binders vals = do valNames <- replicateM (length vals) freshName- let assignments = zipWith (JSVariableIntroduction Nothing) valNames (map Just vals)+ let assignments = zipWith (AST.VariableIntroduction Nothing) valNames (map Just vals) jss <- forM binders $ \(CaseAlternative bs result) -> do ret <- guardsToJs result go valNames ret bs- return $ JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing (assignments ++ concat jss ++ [JSThrow Nothing $ failedPatternError valNames])))+ return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (assignments ++ concat jss ++ [AST.Throw Nothing $ failedPatternError valNames]))) [] where- go :: [Text] -> [JS] -> [Binder Ann] -> m [JS]+ go :: [Text] -> [AST] -> [Binder Ann] -> m [AST] go _ done [] = return done go (v:vs) done' (b:bs) = do done'' <- go vs done' bs binderToJs v done'' b go _ _ _ = internalError "Invalid arguments to bindersToJs" - failedPatternError :: [Text] -> JS- failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing $ mkString failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]+ failedPatternError :: [Text] -> AST+ failedPatternError names = AST.Unary Nothing AST.New $ AST.App Nothing (AST.Var Nothing "Error") [AST.Binary Nothing AST.Add (AST.StringLiteral Nothing $ mkString failedPatternMessage) (AST.ArrayLiteral Nothing $ zipWith valueError names vals)] failedPatternMessage :: Text failedPatternMessage = "Failed pattern match" <> maybe "" (((" at " <> runModuleName mn <> " ") <>) . displayStartEndPos) maybeSpan <> ": " - valueError :: Text -> JS -> JS- valueError _ l@(JSNumericLiteral _ _) = l- valueError _ l@(JSStringLiteral _ _) = l- valueError _ l@(JSBooleanLiteral _ _) = l- valueError s _ = accessorString "name" . accessorString "constructor" $ JSVar Nothing s+ valueError :: Text -> AST -> AST+ valueError _ l@(AST.NumericLiteral _ _) = l+ valueError _ l@(AST.StringLiteral _ _) = l+ valueError _ l@(AST.BooleanLiteral _ _) = l+ valueError s _ = accessorString "name" . accessorString "constructor" $ AST.Var Nothing s - guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [JS]- guardsToJs (Left gs) = forM gs $ \(cond, val) -> do- cond' <- valueToJs cond- done <- valueToJs val- return $ JSIfElse Nothing cond' (JSBlock Nothing [JSReturn Nothing done]) Nothing- guardsToJs (Right v) = return . JSReturn Nothing <$> valueToJs v+ guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [AST]+ guardsToJs (Left gs) = snd <$> F.foldrM genGuard (False, []) gs+ where+ genGuard (cond, val) (False, js) = second (: js) <$> genCondVal cond val+ genGuard _ x = pure x - binderToJs :: Text -> [JS] -> Binder Ann -> m [JS]+ genCondVal cond val+ | condIsTrue cond = do+ js <- AST.Return Nothing <$> valueToJs val+ return (True, js)+ | otherwise = do+ cond' <- valueToJs cond+ val' <- valueToJs val+ return+ (False, AST.IfElse Nothing cond'+ (AST.Block Nothing [AST.Return Nothing val']) Nothing)++ -- hopefully the inliner did its job and inlined `otherwise`+ condIsTrue (Literal _ (BooleanLiteral True)) = True+ condIsTrue _ = False++ guardsToJs (Right v) = return . AST.Return Nothing <$> valueToJs v++ binderToJs :: Text -> [AST] -> Binder Ann -> m [AST] binderToJs s done binder = let (ss, _, _, _) = extractBinderAnn binder in traverse (withPos ss) =<< binderToJs' s done binder - -- |- -- Generate code in the simplified Javascript intermediate representation for a pattern match+ -- | Generate code in the simplified JavaScript intermediate representation for a pattern match -- binder.- --- binderToJs' :: Text -> [JS] -> Binder Ann -> m [JS]+ binderToJs' :: Text -> [AST] -> Binder Ann -> m [AST] binderToJs' _ done NullBinder{} = return done binderToJs' varName done (LiteralBinder _ l) = literalToBinderJS varName done l binderToJs' varName done (VarBinder _ ident) =- return (JSVariableIntroduction Nothing (identToJs ident) (Just (JSVar Nothing varName)) : done)+ return (AST.VariableIntroduction Nothing (identToJs ident) (Just (AST.Var Nothing varName)) : done) binderToJs' varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) = binderToJs varName done b binderToJs' varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ ctor bs) = do@@ -382,68 +371,68 @@ return $ case ctorType of ProductType -> js SumType ->- [JSIfElse Nothing (JSInstanceOf Nothing (JSVar Nothing varName) (qualifiedToJS (Ident . runProperName) ctor))- (JSBlock Nothing js)+ [AST.IfElse Nothing (AST.InstanceOf Nothing (AST.Var Nothing varName) (qualifiedToJS (Ident . runProperName) ctor))+ (AST.Block Nothing js) Nothing] where- go :: [(Ident, Binder Ann)] -> [JS] -> m [JS]+ go :: [(Ident, Binder Ann)] -> [AST] -> m [AST] go [] done' = return done' go ((field, binder) : remain) done' = do argVar <- freshName done'' <- go remain done' js <- binderToJs argVar done'' binder- return (JSVariableIntroduction Nothing argVar (Just $ accessorString (mkString $ identToJs field) $ JSVar Nothing varName) : js)+ return (AST.VariableIntroduction Nothing argVar (Just $ accessorString (mkString $ identToJs field) $ AST.Var Nothing varName) : js) binderToJs' _ _ ConstructorBinder{} = internalError "binderToJs: Invalid ConstructorBinder in binderToJs" binderToJs' varName done (NamedBinder _ ident binder) = do js <- binderToJs varName done binder- return (JSVariableIntroduction Nothing (identToJs ident) (Just (JSVar Nothing varName)) : js)+ return (AST.VariableIntroduction Nothing (identToJs ident) (Just (AST.Var Nothing varName)) : js) - literalToBinderJS :: Text -> [JS] -> Literal (Binder Ann) -> m [JS]+ literalToBinderJS :: Text -> [AST] -> Literal (Binder Ann) -> m [AST] literalToBinderJS varName done (NumericLiteral num) =- return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSNumericLiteral Nothing num)) (JSBlock Nothing done) Nothing]+ return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.NumericLiteral Nothing num)) (AST.Block Nothing done) Nothing] literalToBinderJS varName done (CharLiteral c) =- return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing (fromString [c]))) (JSBlock Nothing done) Nothing]+ return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing (fromString [c]))) (AST.Block Nothing done) Nothing] literalToBinderJS varName done (StringLiteral str) =- return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing str)) (JSBlock Nothing done) Nothing]+ return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing str)) (AST.Block Nothing done) Nothing] literalToBinderJS varName done (BooleanLiteral True) =- return [JSIfElse Nothing (JSVar Nothing varName) (JSBlock Nothing done) Nothing]+ return [AST.IfElse Nothing (AST.Var Nothing varName) (AST.Block Nothing done) Nothing] literalToBinderJS varName done (BooleanLiteral False) =- return [JSIfElse Nothing (JSUnary Nothing Not (JSVar Nothing varName)) (JSBlock Nothing done) Nothing]+ return [AST.IfElse Nothing (AST.Unary Nothing AST.Not (AST.Var Nothing varName)) (AST.Block Nothing done) Nothing] literalToBinderJS varName done (ObjectLiteral bs) = go done bs where- go :: [JS] -> [(PSString, Binder Ann)] -> m [JS]+ go :: [AST] -> [(PSString, Binder Ann)] -> m [AST] go done' [] = return done' go done' ((prop, binder):bs') = do propVar <- freshName done'' <- go done' bs' js <- binderToJs propVar done'' binder- return (JSVariableIntroduction Nothing propVar (Just (accessorString prop (JSVar Nothing varName))) : js)+ return (AST.VariableIntroduction Nothing propVar (Just (accessorString prop (AST.Var Nothing varName))) : js) literalToBinderJS varName done (ArrayLiteral bs) = do js <- go done 0 bs- return [JSIfElse Nothing (JSBinary Nothing EqualTo (accessorString "length" (JSVar Nothing varName)) (JSNumericLiteral Nothing (Left (fromIntegral $ length bs)))) (JSBlock Nothing js) Nothing]+ return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (accessorString "length" (AST.Var Nothing varName)) (AST.NumericLiteral Nothing (Left (fromIntegral $ length bs)))) (AST.Block Nothing js) Nothing] where- go :: [JS] -> Integer -> [Binder Ann] -> m [JS]+ go :: [AST] -> Integer -> [Binder Ann] -> m [AST] go done' _ [] = return done' go done' index (binder:bs') = do elVar <- freshName done'' <- go done' (index + 1) bs' js <- binderToJs elVar done'' binder- return (JSVariableIntroduction Nothing elVar (Just (JSIndexer Nothing (JSNumericLiteral Nothing (Left index)) (JSVar Nothing varName))) : js)+ return (AST.VariableIntroduction Nothing elVar (Just (AST.Indexer Nothing (AST.NumericLiteral Nothing (Left index)) (AST.Var Nothing varName))) : js) -- Check that all integers fall within the valid int range for JavaScript.- checkIntegers :: JS -> m ()- checkIntegers = void . everywhereOnJSTopDownM go+ checkIntegers :: AST -> m ()+ checkIntegers = void . everywhereTopDownM go where- go :: JS -> m JS- go (JSUnary _ Negate (JSNumericLiteral ss (Left i))) =+ go :: AST -> m AST+ go (AST.Unary _ AST.Negate (AST.NumericLiteral ss (Left i))) = -- Move the negation inside the literal; since this is a top-down -- traversal doing this replacement will stop the next case from raising -- the error when attempting to use -2147483648, as if left unrewritten- -- the value is `JSUnary Negate (JSNumericLiteral (Left 2147483648))`, and+ -- the value is `Unary Negate (NumericLiteral (Left 2147483648))`, and -- 2147483648 is larger than the maximum allowed int.- return $ JSNumericLiteral ss (Left (-i))- go js@(JSNumericLiteral _ (Left i)) =+ return $ AST.NumericLiteral ss (Left (-i))+ go js@(AST.NumericLiteral _ (Left i)) = let minInt = -2147483648 maxInt = 2147483647 in if i < minInt || i > maxInt
− src/Language/PureScript/CodeGen/JS/AST.hs
@@ -1,398 +0,0 @@--- |--- Data types for the intermediate simplified-Javascript AST----module Language.PureScript.CodeGen.JS.AST where--import Prelude.Compat--import Control.Monad ((>=>))-import Control.Monad.Identity (Identity(..), runIdentity)-import Data.Text (Text)--import Language.PureScript.AST (SourceSpan(..))-import Language.PureScript.Comments-import Language.PureScript.PSString (PSString)-import Language.PureScript.Traversals---- |--- Built-in unary operators----data UnaryOperator- -- |- -- Numeric negation- --- = Negate- -- |- -- Boolean negation- --- | Not- -- |- -- Bitwise negation- --- | BitwiseNot- -- |- -- Numeric unary \'plus\'- --- | Positive- -- |- -- Constructor- --- | JSNew- deriving (Show, Eq)---- |--- Built-in binary operators----data BinaryOperator- -- |- -- Numeric addition- --- = Add- -- |- -- Numeric subtraction- --- | Subtract- -- |- -- Numeric multiplication- --- | Multiply- -- |- -- Numeric division- --- | Divide- -- |- -- Remainder- --- | Modulus- -- |- -- Generic equality test- --- | EqualTo- -- |- -- Generic inequality test- --- | NotEqualTo- -- |- -- Numeric less-than- --- | LessThan- -- |- -- Numeric less-than-or-equal- --- | LessThanOrEqualTo- -- |- -- Numeric greater-than- --- | GreaterThan- -- |- -- Numeric greater-than-or-equal- --- | GreaterThanOrEqualTo- -- |- -- Boolean and- --- | And- -- |- -- Boolean or- --- | Or- -- |- -- Bitwise and- --- | BitwiseAnd- -- |- -- Bitwise or- --- | BitwiseOr- -- |- -- Bitwise xor- --- | BitwiseXor- -- |- -- Bitwise left shift- --- | ShiftLeft- -- |- -- Bitwise right shift- --- | ShiftRight- -- |- -- Bitwise right shift with zero-fill- --- | ZeroFillShiftRight- deriving (Show, Eq)---- |--- Data type for simplified Javascript expressions----data JS- -- |- -- A numeric literal- --- = JSNumericLiteral (Maybe SourceSpan) (Either Integer Double)- -- |- -- A string literal- --- | JSStringLiteral (Maybe SourceSpan) PSString- -- |- -- A boolean literal- --- | JSBooleanLiteral (Maybe SourceSpan) Bool- -- |- -- A unary operator application- --- | JSUnary (Maybe SourceSpan) UnaryOperator JS- -- |- -- A binary operator application- --- | JSBinary (Maybe SourceSpan) BinaryOperator JS JS- -- |- -- An array literal- --- | JSArrayLiteral (Maybe SourceSpan) [JS]- -- |- -- An array indexer expression- --- | JSIndexer (Maybe SourceSpan) JS JS- -- |- -- An object literal- --- | JSObjectLiteral (Maybe SourceSpan) [(PSString, JS)]- -- |- -- A function introduction (optional name, arguments, body)- --- | JSFunction (Maybe SourceSpan) (Maybe Text) [Text] JS- -- |- -- Function application- --- | JSApp (Maybe SourceSpan) JS [JS]- -- |- -- Variable- --- | JSVar (Maybe SourceSpan) Text- -- |- -- Conditional expression- --- | JSConditional (Maybe SourceSpan) JS JS JS- -- |- -- A block of expressions in braces- --- | JSBlock (Maybe SourceSpan) [JS]- -- |- -- A variable introduction and optional initialization- --- | JSVariableIntroduction (Maybe SourceSpan) Text (Maybe JS)- -- |- -- A variable assignment- --- | JSAssignment (Maybe SourceSpan) JS JS- -- |- -- While loop- --- | JSWhile (Maybe SourceSpan) JS JS- -- |- -- For loop- --- | JSFor (Maybe SourceSpan) Text JS JS JS- -- |- -- ForIn loop- --- | JSForIn (Maybe SourceSpan) Text JS JS- -- |- -- If-then-else statement- --- | JSIfElse (Maybe SourceSpan) JS JS (Maybe JS)- -- |- -- Return statement- --- | JSReturn (Maybe SourceSpan) JS- -- |- -- Throw statement- --- | JSThrow (Maybe SourceSpan) JS- -- |- -- Type-Of operator- --- | JSTypeOf (Maybe SourceSpan) JS- -- |- -- InstanceOf test- --- | JSInstanceOf (Maybe SourceSpan) JS JS- -- |- -- Labelled statement- --- | JSLabel (Maybe SourceSpan) Text JS- -- |- -- Break statement- --- | JSBreak (Maybe SourceSpan) Text- -- |- -- Continue statement- --- | JSContinue (Maybe SourceSpan) Text- -- |- -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)- --- | JSRaw (Maybe SourceSpan) Text- -- |- -- Commented Javascript- --- | JSComment (Maybe SourceSpan) [Comment] JS- deriving (Show, Eq)--withSourceSpan :: SourceSpan -> JS -> JS-withSourceSpan withSpan = go- where- ss :: Maybe SourceSpan- ss = Just withSpan-- go :: JS -> JS- go (JSNumericLiteral _ n) = JSNumericLiteral ss n- go (JSStringLiteral _ s) = JSStringLiteral ss s- go (JSBooleanLiteral _ b) = JSBooleanLiteral ss b- go (JSUnary _ op j) = JSUnary ss op j- go (JSBinary _ op j1 j2) = JSBinary ss op j1 j2- go (JSArrayLiteral _ js) = JSArrayLiteral ss js- go (JSIndexer _ j1 j2) = JSIndexer ss j1 j2- go (JSObjectLiteral _ js) = JSObjectLiteral ss js- go (JSFunction _ name args j) = JSFunction ss name args j- go (JSApp _ j js) = JSApp ss j js- go (JSVar _ s) = JSVar ss s- go (JSConditional _ j1 j2 j3) = JSConditional ss j1 j2 j3- go (JSBlock _ js) = JSBlock ss js- go (JSVariableIntroduction _ name j) = JSVariableIntroduction ss name j- go (JSAssignment _ j1 j2) = JSAssignment ss j1 j2- go (JSWhile _ j1 j2) = JSWhile ss j1 j2- go (JSFor _ name j1 j2 j3) = JSFor ss name j1 j2 j3- go (JSForIn _ name j1 j2) = JSForIn ss name j1 j2- go (JSIfElse _ j1 j2 j3) = JSIfElse ss j1 j2 j3- go (JSReturn _ js) = JSReturn ss js- go (JSThrow _ js) = JSThrow ss js- go (JSTypeOf _ js) = JSTypeOf ss js- go (JSInstanceOf _ j1 j2) = JSInstanceOf ss j1 j2- go (JSLabel _ name js) = JSLabel ss name js- go (JSBreak _ s) = JSBreak ss s- go (JSContinue _ s) = JSContinue ss s- go (JSRaw _ s) = JSRaw ss s- go (JSComment _ com j) = JSComment ss com j--getSourceSpan :: JS -> Maybe SourceSpan-getSourceSpan = go- where- go :: JS -> Maybe SourceSpan- go (JSNumericLiteral ss _) = ss- go (JSStringLiteral ss _) = ss- go (JSBooleanLiteral ss _) = ss- go (JSUnary ss _ _) = ss- go (JSBinary ss _ _ _) = ss- go (JSArrayLiteral ss _) = ss- go (JSIndexer ss _ _) = ss- go (JSObjectLiteral ss _) = ss- go (JSFunction ss _ _ _) = ss- go (JSApp ss _ _) = ss- go (JSVar ss _) = ss- go (JSConditional ss _ _ _) = ss- go (JSBlock ss _) = ss- go (JSVariableIntroduction ss _ _) = ss- go (JSAssignment ss _ _) = ss- go (JSWhile ss _ _) = ss- go (JSFor ss _ _ _ _) = ss- go (JSForIn ss _ _ _) = ss- go (JSIfElse ss _ _ _) = ss- go (JSReturn ss _) = ss- go (JSThrow ss _) = ss- go (JSTypeOf ss _) = ss- go (JSInstanceOf ss _ _) = ss- go (JSLabel ss _ _) = ss- go (JSBreak ss _) = ss- go (JSContinue ss _) = ss- go (JSRaw ss _) = ss- go (JSComment ss _ _) = ss------- Traversals-----everywhereOnJS :: (JS -> JS) -> JS -> JS-everywhereOnJS f = go- where- go :: JS -> JS- go (JSUnary ss op j) = f (JSUnary ss op (go j))- go (JSBinary ss op j1 j2) = f (JSBinary ss op (go j1) (go j2))- go (JSArrayLiteral ss js) = f (JSArrayLiteral ss (map go js))- go (JSIndexer ss j1 j2) = f (JSIndexer ss (go j1) (go j2))- go (JSObjectLiteral ss js) = f (JSObjectLiteral ss (map (fmap go) js))- go (JSFunction ss name args j) = f (JSFunction ss name args (go j))- go (JSApp ss j js) = f (JSApp ss (go j) (map go js))- go (JSConditional ss j1 j2 j3) = f (JSConditional ss (go j1) (go j2) (go j3))- go (JSBlock ss js) = f (JSBlock ss (map go js))- go (JSVariableIntroduction ss name j) = f (JSVariableIntroduction ss name (fmap go j))- go (JSAssignment ss j1 j2) = f (JSAssignment ss (go j1) (go j2))- go (JSWhile ss j1 j2) = f (JSWhile ss (go j1) (go j2))- go (JSFor ss name j1 j2 j3) = f (JSFor ss name (go j1) (go j2) (go j3))- go (JSForIn ss name j1 j2) = f (JSForIn ss name (go j1) (go j2))- go (JSIfElse ss j1 j2 j3) = f (JSIfElse ss (go j1) (go j2) (fmap go j3))- go (JSReturn ss js) = f (JSReturn ss (go js))- go (JSThrow ss js) = f (JSThrow ss (go js))- go (JSTypeOf ss js) = f (JSTypeOf ss (go js))- go (JSLabel ss name js) = f (JSLabel ss name (go js))- go (JSInstanceOf ss j1 j2) = f (JSInstanceOf ss (go j1) (go j2))- go (JSComment ss com j) = f (JSComment ss com (go j))- go other = f other--everywhereOnJSTopDown :: (JS -> JS) -> JS -> JS-everywhereOnJSTopDown f = runIdentity . everywhereOnJSTopDownM (Identity . f)--everywhereOnJSTopDownM :: (Monad m) => (JS -> m JS) -> JS -> m JS-everywhereOnJSTopDownM f = f >=> go- where- f' = f >=> go- go (JSUnary ss op j) = JSUnary ss op <$> f' j- go (JSBinary ss op j1 j2) = JSBinary ss op <$> f' j1 <*> f' j2- go (JSArrayLiteral ss js) = JSArrayLiteral ss <$> traverse f' js- go (JSIndexer ss j1 j2) = JSIndexer ss <$> f' j1 <*> f' j2- go (JSObjectLiteral ss js) = JSObjectLiteral ss <$> traverse (sndM f') js- go (JSFunction ss name args j) = JSFunction ss name args <$> f' j- go (JSApp ss j js) = JSApp ss <$> f' j <*> traverse f' js- go (JSConditional ss j1 j2 j3) = JSConditional ss <$> f' j1 <*> f' j2 <*> f' j3- go (JSBlock ss js) = JSBlock ss <$> traverse f' js- go (JSVariableIntroduction ss name j) = JSVariableIntroduction ss name <$> traverse f' j- go (JSAssignment ss j1 j2) = JSAssignment ss <$> f' j1 <*> f' j2- go (JSWhile ss j1 j2) = JSWhile ss <$> f' j1 <*> f' j2- go (JSFor ss name j1 j2 j3) = JSFor ss name <$> f' j1 <*> f' j2 <*> f' j3- go (JSForIn ss name j1 j2) = JSForIn ss name <$> f' j1 <*> f' j2- go (JSIfElse ss j1 j2 j3) = JSIfElse ss <$> f' j1 <*> f' j2 <*> traverse f' j3- go (JSReturn ss j) = JSReturn ss <$> f' j- go (JSThrow ss j) = JSThrow ss <$> f' j- go (JSTypeOf ss j) = JSTypeOf ss <$> f' j- go (JSLabel ss name j) = JSLabel ss name <$> f' j- go (JSInstanceOf ss j1 j2) = JSInstanceOf ss <$> f' j1 <*> f' j2- go (JSComment ss com j) = JSComment ss com <$> f' j- go other = f other--everythingOnJS :: (r -> r -> r) -> (JS -> r) -> JS -> r-everythingOnJS (<>) f = go- where- go j@(JSUnary _ _ j1) = f j <> go j1- go j@(JSBinary _ _ j1 j2) = f j <> go j1 <> go j2- go j@(JSArrayLiteral _ js) = foldl (<>) (f j) (map go js)- go j@(JSIndexer _ j1 j2) = f j <> go j1 <> go j2- go j@(JSObjectLiteral _ js) = foldl (<>) (f j) (map (go . snd) js)- go j@(JSFunction _ _ _ j1) = f j <> go j1- go j@(JSApp _ j1 js) = foldl (<>) (f j <> go j1) (map go js)- go j@(JSConditional _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3- go j@(JSBlock _ js) = foldl (<>) (f j) (map go js)- go j@(JSVariableIntroduction _ _ (Just j1)) = f j <> go j1- go j@(JSAssignment _ j1 j2) = f j <> go j1 <> go j2- go j@(JSWhile _ j1 j2) = f j <> go j1 <> go j2- go j@(JSFor _ _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3- go j@(JSForIn _ _ j1 j2) = f j <> go j1 <> go j2- go j@(JSIfElse _ j1 j2 Nothing) = f j <> go j1 <> go j2- go j@(JSIfElse _ j1 j2 (Just j3)) = f j <> go j1 <> go j2 <> go j3- go j@(JSReturn _ j1) = f j <> go j1- go j@(JSThrow _ j1) = f j <> go j1- go j@(JSTypeOf _ j1) = f j <> go j1- go j@(JSLabel _ _ j1) = f j <> go j1- go j@(JSInstanceOf _ j1 j2) = f j <> go j1 <> go j2- go j@(JSComment _ _ j1) = f j <> go j1- go other = f other
src/Language/PureScript/CodeGen/JS/Common.hs view
@@ -1,6 +1,4 @@--- |--- Common code generation utility functions---+-- | Common code generation utility functions module Language.PureScript.CodeGen.JS.Common where import Prelude.Compat@@ -18,15 +16,13 @@ let name = T.intercalate "_" (runProperName `map` pns) in if nameIsJsBuiltIn name then "$$" <> name else name --- |--- Convert an Ident into a valid Javascript identifier:+-- | Convert an 'Ident' into a valid JavaScript identifier: -- -- * Alphanumeric characters are kept unmodified. -- -- * Reserved javascript identifiers are prefixed with '$$'. -- -- * Symbols are prefixed with '$' followed by a symbol name or their ordinal value.--- identToJs :: Ident -> Text identToJs (Ident name) = properToJs name identToJs (GenIdent _ _) = internalError "GenIdent in identToJs"@@ -36,16 +32,12 @@ | nameIsJsReserved name || nameIsJsBuiltIn name = "$$" <> name | otherwise = T.concatMap identCharToText name --- |--- Test if a string is a valid JS identifier without escaping.---+-- | Test if a string is a valid AST identifier without escaping. identNeedsEscaping :: Text -> Bool identNeedsEscaping s = s /= properToJs s || T.null s --- |--- Attempts to find a human-readable name for a symbol, if none has been specified returns the+-- | Attempts to find a human-readable name for a symbol, if none has been specified returns the -- ordinal value.--- identCharToText :: Char -> Text identCharToText c | isAlphaNum c = T.singleton c identCharToText '_' = "_"@@ -72,16 +64,12 @@ identCharToText '\'' = "$prime" identCharToText c = '$' `T.cons` T.pack (show (ord c)) --- |--- Checks whether an identifier name is reserved in Javascript.---+-- | Checks whether an identifier name is reserved in JavaScript. nameIsJsReserved :: Text -> Bool nameIsJsReserved name = name `elem` jsAnyReserved --- |--- Checks whether a name matches a built-in value in Javascript.---+-- | Checks whether a name matches a built-in value in JavaScript. nameIsJsBuiltIn :: Text -> Bool nameIsJsBuiltIn name = name `elem`
− src/Language/PureScript/CodeGen/JS/Optimizer.hs
@@ -1,73 +0,0 @@--- |--- This module optimizes code in the simplified-Javascript intermediate representation.------ The following optimizations are supported:------ * Collapsing nested blocks------ * Tail call elimination------ * Inlining of (>>=) and ret for the Eff monad------ * Removal of unnecessary thunks------ * Eta conversion------ * Inlining variables------ * Inline Prelude.($), Prelude.(#), Prelude.(++), Prelude.(!!)------ * Inlining primitive Javascript operators----module Language.PureScript.CodeGen.JS.Optimizer (optimize) where--import Prelude.Compat--import Control.Monad.Reader (MonadReader, ask, asks)-import Control.Monad.Supply.Class (MonadSupply)--import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.CodeGen.JS.Optimizer.Blocks-import Language.PureScript.CodeGen.JS.Optimizer.Common-import Language.PureScript.CodeGen.JS.Optimizer.Inliner-import Language.PureScript.CodeGen.JS.Optimizer.MagicDo-import Language.PureScript.CodeGen.JS.Optimizer.TCO-import Language.PureScript.CodeGen.JS.Optimizer.Unused-import Language.PureScript.Options---- |--- Apply a series of optimizer passes to simplified Javascript code----optimize :: (MonadReader Options m, MonadSupply m) => JS -> m JS-optimize js = do- noOpt <- asks optionsNoOptimizations- if noOpt then return js else optimize' js--optimize' :: (MonadReader Options m, MonadSupply m) => JS -> m JS-optimize' js = do- opts <- ask- js' <- untilFixedPoint (inlineFnComposition . inlineUnsafePartial . tidyUp . applyAll- [ inlineCommonValues- , inlineCommonOperators- ]) js- untilFixedPoint (return . tidyUp) . tco opts . magicDo opts $ js'- where- tidyUp :: JS -> JS- tidyUp = applyAll- [ collapseNestedBlocks- , collapseNestedIfs- , removeCodeAfterReturnStatements- , removeUnusedArg- , removeUndefinedApp- , unThunk- , etaConvert- , evaluateIifes- , inlineVariables- ]--untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a-untilFixedPoint f = go- where- go a = do- a' <- f a- if a' == a then return a' else go a'
− src/Language/PureScript/CodeGen/JS/Optimizer/Blocks.hs
@@ -1,32 +0,0 @@--- |--- Optimizer steps for simplifying Javascript blocks----module Language.PureScript.CodeGen.JS.Optimizer.Blocks- ( collapseNestedBlocks- , collapseNestedIfs- ) where--import Prelude.Compat--import Language.PureScript.CodeGen.JS.AST---- |--- Collapse blocks which appear nested directly below another block----collapseNestedBlocks :: JS -> JS-collapseNestedBlocks = everywhereOnJS collapse- where- collapse :: JS -> JS- collapse (JSBlock ss sts) = JSBlock ss (concatMap go sts)- collapse js = js- go :: JS -> [JS]- go (JSBlock _ sts) = sts- go s = [s]--collapseNestedIfs :: JS -> JS-collapseNestedIfs = everywhereOnJS collapse- where- collapse :: JS -> JS- collapse (JSIfElse s1 cond1 (JSBlock _ [JSIfElse s2 cond2 body Nothing]) Nothing) =- JSIfElse s1 (JSBinary s2 And cond1 cond2) body Nothing- collapse js = js
− src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs
@@ -1,78 +0,0 @@--- |--- Common functions used by the various optimizer phases----module Language.PureScript.CodeGen.JS.Optimizer.Common where--import Prelude.Compat--import Data.Text (Text)-import Data.List (foldl')-import Data.Maybe (fromMaybe)--import Language.PureScript.Crash-import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.PSString (PSString)--applyAll :: [a -> a] -> a -> a-applyAll = foldl' (.) id--replaceIdent :: Text -> JS -> JS -> JS-replaceIdent var1 js = everywhereOnJS replace- where- replace (JSVar _ var2) | var1 == var2 = js- replace other = other--replaceIdents :: [(Text, JS)] -> JS -> JS-replaceIdents vars = everywhereOnJS replace- where- replace v@(JSVar _ var) = fromMaybe v $ lookup var vars- replace other = other--isReassigned :: Text -> JS -> Bool-isReassigned var1 = everythingOnJS (||) check- where- check :: JS -> Bool- check (JSFunction _ _ args _) | var1 `elem` args = True- check (JSVariableIntroduction _ arg _) | var1 == arg = True- check (JSAssignment _ (JSVar _ arg) _) | var1 == arg = True- check (JSFor _ arg _ _ _) | var1 == arg = True- check (JSForIn _ arg _ _) | var1 == arg = True- check _ = False--isRebound :: JS -> JS -> Bool-isRebound js d = any (\v -> isReassigned v d || isUpdated v d) (everythingOnJS (++) variablesOf js)- where- variablesOf (JSVar _ var) = [var]- variablesOf _ = []--isUsed :: Text -> JS -> Bool-isUsed var1 = everythingOnJS (||) check- where- check :: JS -> Bool- check (JSVar _ var2) | var1 == var2 = True- check (JSAssignment _ target _) | var1 == targetVariable target = True- check _ = False--targetVariable :: JS -> Text-targetVariable (JSVar _ var) = var-targetVariable (JSIndexer _ _ tgt) = targetVariable tgt-targetVariable _ = internalError "Invalid argument to targetVariable"--isUpdated :: Text -> JS -> Bool-isUpdated var1 = everythingOnJS (||) check- where- check :: JS -> Bool- check (JSAssignment _ target _) | var1 == targetVariable target = True- check _ = False--removeFromBlock :: ([JS] -> [JS]) -> JS -> JS-removeFromBlock go (JSBlock ss sts) = JSBlock ss (go sts)-removeFromBlock _ js = js--isDict :: (Text, PSString) -> JS -> Bool-isDict (moduleName, dictName) (JSIndexer _ (JSStringLiteral _ x) (JSVar _ y)) =- x == dictName && y == moduleName-isDict _ _ = False--isDict' :: [(Text, PSString)] -> JS -> Bool-isDict' xs js = any (`isDict` js) xs
− src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs
@@ -1,385 +0,0 @@--- |--- This module provides basic inlining capabilities----module Language.PureScript.CodeGen.JS.Optimizer.Inliner- ( inlineVariables- , inlineCommonValues- , inlineCommonOperators- , inlineFnComposition- , inlineUnsafePartial- , etaConvert- , unThunk- , evaluateIifes- ) where--import Prelude.Compat--import Control.Monad.Supply.Class (MonadSupply, freshName)--import Data.Maybe (fromMaybe)-import Data.Monoid ((<>))-import Data.String (IsString, fromString)-import Data.Text (Text)-import qualified Data.Text as T--import Language.PureScript.PSString (PSString)-import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.CodeGen.JS.Optimizer.Common-import qualified Language.PureScript.Constants as C---- TODO: Potential bug:--- Shouldn't just inline this case: { var x = 0; x.toFixed(10); }--- Needs to be: { 0..toFixed(10); }--- Probably needs to be fixed in pretty-printer instead.-shouldInline :: JS -> Bool-shouldInline (JSVar _ _) = True-shouldInline (JSNumericLiteral _ _) = True-shouldInline (JSStringLiteral _ _) = True-shouldInline (JSBooleanLiteral _ _) = True-shouldInline (JSIndexer _ index val) = shouldInline index && shouldInline val-shouldInline _ = False--etaConvert :: JS -> JS-etaConvert = everywhereOnJS convert- where- convert :: JS -> JS- convert (JSBlock ss [JSReturn _ (JSApp _ (JSFunction _ Nothing idents block@(JSBlock _ body)) args)])- | all shouldInline args &&- not (any (`isRebound` block) (map (JSVar Nothing) idents)) &&- not (any (`isRebound` block) args)- = JSBlock ss (map (replaceIdents (zip idents args)) body)- convert (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ (JSApp _ fn [])])) = fn- convert js = js--unThunk :: JS -> JS-unThunk = everywhereOnJS convert- where- convert :: JS -> JS- convert (JSBlock ss []) = JSBlock ss []- convert (JSBlock ss jss) =- case last jss of- JSReturn _ (JSApp _ (JSFunction _ Nothing [] (JSBlock _ body)) []) -> JSBlock ss $ init jss ++ body- _ -> JSBlock ss jss- convert js = js--evaluateIifes :: JS -> JS-evaluateIifes = everywhereOnJS convert- where- convert :: JS -> JS- convert (JSApp _ (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ ret])) []) = ret- convert (JSApp _ (JSFunction _ Nothing idents (JSBlock _ [JSReturn ss ret])) [])- | not (any (`isReassigned` ret) idents) = replaceIdents (map (, JSVar ss C.undefined) idents) ret- convert js = js--inlineVariables :: JS -> JS-inlineVariables = everywhereOnJS $ removeFromBlock go- where- go :: [JS] -> [JS]- go [] = []- go (JSVariableIntroduction _ var (Just js) : sts)- | shouldInline js && not (any (isReassigned var) sts) && not (any (isRebound js) sts) && not (any (isUpdated var) sts) =- go (map (replaceIdent var js) sts)- go (s:sts) = s : go sts--inlineCommonValues :: JS -> JS-inlineCommonValues = everywhereOnJS convert- where- convert :: JS -> JS- convert (JSApp ss fn [dict])- | isDict' [semiringNumber, semiringInt] dict && isDict fnZero fn = JSNumericLiteral ss (Left 0)- | isDict' [semiringNumber, semiringInt] dict && isDict fnOne fn = JSNumericLiteral ss (Left 1)- | isDict boundedBoolean dict && isDict fnBottom fn = JSBooleanLiteral ss False- | isDict boundedBoolean dict && isDict fnTop fn = JSBooleanLiteral ss True- convert (JSApp ss (JSApp _ fn [dict]) [x])- | isDict ringInt dict && isDict fnNegate fn = JSBinary ss BitwiseOr (JSUnary ss Negate x) (JSNumericLiteral ss (Left 0))- convert (JSApp ss (JSApp _ (JSApp _ fn [dict]) [x]) [y])- | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add x y- | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply x y- | isDict euclideanRingInt dict && isDict fnDivide fn = intOp ss Divide x y- | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract x y- convert other = other- fnZero = (C.dataSemiring, C.zero)- fnOne = (C.dataSemiring, C.one)- fnBottom = (C.dataBounded, C.bottom)- fnTop = (C.dataBounded, C.top)- fnAdd = (C.dataSemiring, C.add)- fnDivide = (C.dataEuclideanRing, C.div)- fnMultiply = (C.dataSemiring, C.mul)- fnSubtract = (C.dataRing, C.sub)- fnNegate = (C.dataRing, C.negate)- intOp ss op x y = JSBinary ss BitwiseOr (JSBinary ss op x y) (JSNumericLiteral ss (Left 0))--inlineCommonOperators :: JS -> JS-inlineCommonOperators = everywhereOnJSTopDown $ applyAll $- [ binary semiringNumber opAdd Add- , binary semiringNumber opMul Multiply-- , binary ringNumber opSub Subtract- , unary ringNumber opNegate Negate-- , binary euclideanRingNumber opDiv Divide- , binary euclideanRingInt opMod Modulus-- , binary eqNumber opEq EqualTo- , binary eqNumber opNotEq NotEqualTo- , binary eqInt opEq EqualTo- , binary eqInt opNotEq NotEqualTo- , binary eqString opEq EqualTo- , binary eqString opNotEq NotEqualTo- , binary eqChar opEq EqualTo- , binary eqChar opNotEq NotEqualTo- , binary eqBoolean opEq EqualTo- , binary eqBoolean opNotEq NotEqualTo-- , binary ordBoolean opLessThan LessThan- , binary ordBoolean opLessThanOrEq LessThanOrEqualTo- , binary ordBoolean opGreaterThan GreaterThan- , binary ordBoolean opGreaterThanOrEq GreaterThanOrEqualTo- , binary ordChar opLessThan LessThan- , binary ordChar opLessThanOrEq LessThanOrEqualTo- , binary ordChar opGreaterThan GreaterThan- , binary ordChar opGreaterThanOrEq GreaterThanOrEqualTo- , binary ordInt opLessThan LessThan- , binary ordInt opLessThanOrEq LessThanOrEqualTo- , binary ordInt opGreaterThan GreaterThan- , binary ordInt opGreaterThanOrEq GreaterThanOrEqualTo- , binary ordNumber opLessThan LessThan- , binary ordNumber opLessThanOrEq LessThanOrEqualTo- , binary ordNumber opGreaterThan GreaterThan- , binary ordNumber opGreaterThanOrEq GreaterThanOrEqualTo- , binary ordString opLessThan LessThan- , binary ordString opLessThanOrEq LessThanOrEqualTo- , binary ordString opGreaterThan GreaterThan- , binary ordString opGreaterThanOrEq GreaterThanOrEqualTo-- , binary semigroupString opAppend Add-- , binary heytingAlgebraBoolean opConj And- , binary heytingAlgebraBoolean opDisj Or- , unary heytingAlgebraBoolean opNot Not-- , binary' C.dataIntBits C.or BitwiseOr- , binary' C.dataIntBits C.and BitwiseAnd- , binary' C.dataIntBits C.xor BitwiseXor- , binary' C.dataIntBits C.shl ShiftLeft- , binary' C.dataIntBits C.shr ShiftRight- , binary' C.dataIntBits C.zshr ZeroFillShiftRight- , unary' C.dataIntBits C.complement BitwiseNot-- , inlineNonClassFunction (isModFn (C.dataFunction, C.apply)) $ \f x -> JSApp Nothing f [x]- , inlineNonClassFunction (isModFn (C.dataFunction, C.applyFlipped)) $ \x f -> JSApp Nothing f [x]- , inlineNonClassFunction (isModFnWithDict (C.dataArray, C.unsafeIndex)) $ flip (JSIndexer Nothing)- ] ++- [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]- where- binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> JS -> JS- binary dict fns op = convert where- convert :: JS -> JS- convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y]) | isDict dict dict' && isDict fns fn = JSBinary ss op x y- convert other = other- binary' :: Text -> PSString -> BinaryOperator -> JS -> JS- binary' moduleName opString op = convert where- convert :: JS -> JS- convert (JSApp ss (JSApp _ fn [x]) [y]) | isDict (moduleName, opString) fn = JSBinary ss op x y- convert other = other- unary :: (Text, PSString) -> (Text, PSString) -> UnaryOperator -> JS -> JS- unary dicts fns op = convert where- convert :: JS -> JS- convert (JSApp ss (JSApp _ fn [dict']) [x]) | isDict dicts dict' && isDict fns fn = JSUnary ss op x- convert other = other- unary' :: Text -> PSString -> UnaryOperator -> JS -> JS- unary' moduleName fnName op = convert where- convert :: JS -> JS- convert (JSApp ss fn [x]) | isDict (moduleName, fnName) fn = JSUnary ss op x- convert other = other- mkFn :: Int -> JS -> JS- mkFn 0 = convert where- convert :: JS -> JS- convert (JSApp _ mkFnN [JSFunction s1 Nothing [_] (JSBlock s2 js)]) | isNFn C.mkFn 0 mkFnN =- JSFunction s1 Nothing [] (JSBlock s2 js)- convert other = other- mkFn n = convert where- convert :: JS -> JS- convert orig@(JSApp ss mkFnN [fn]) | isNFn C.mkFn n mkFnN =- case collectArgs n [] fn of- Just (args, js) -> JSFunction ss Nothing args (JSBlock ss js)- Nothing -> orig- convert other = other- collectArgs :: Int -> [Text] -> JS -> Maybe ([Text], [JS])- collectArgs 1 acc (JSFunction _ Nothing [oneArg] (JSBlock _ js)) | length acc == n - 1 = Just (reverse (oneArg : acc), js)- collectArgs m acc (JSFunction _ Nothing [oneArg] (JSBlock _ [JSReturn _ ret])) = collectArgs (m - 1) (oneArg : acc) ret- collectArgs _ _ _ = Nothing-- isNFn :: Text -> Int -> JS -> Bool- isNFn prefix n (JSVar _ name) = name == (prefix <> T.pack (show n))- isNFn prefix n (JSIndexer _ (JSStringLiteral _ name) (JSVar _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried =- name == fromString (T.unpack prefix <> show n)- isNFn _ _ _ = False-- runFn :: Int -> JS -> JS- runFn n = convert where- convert :: JS -> JS- convert js = fromMaybe js $ go n [] js-- go :: Int -> [JS] -> JS -> Maybe JS- go 0 acc (JSApp ss runFnN [fn]) | isNFn C.runFn n runFnN && length acc == n = Just (JSApp ss fn acc)- go m acc (JSApp _ lhs [arg]) = go (m - 1) (arg : acc) lhs- go _ _ _ = Nothing-- inlineNonClassFunction :: (JS -> Bool) -> (JS -> JS -> JS) -> JS -> JS- inlineNonClassFunction p f = convert where- convert :: JS -> JS- convert (JSApp _ (JSApp _ op' [x]) [y]) | p op' = f x y- convert other = other-- isModFn :: (Text, PSString) -> JS -> Bool- isModFn (m, op) (JSIndexer _ (JSStringLiteral _ op') (JSVar _ m')) =- m == m' && op == op'- isModFn _ _ = False-- isModFnWithDict :: (Text, PSString) -> JS -> Bool- isModFnWithDict (m, op) (JSApp _ (JSIndexer _ (JSStringLiteral _ op') (JSVar _ m')) [JSVar _ _]) =- m == m' && op == op'- isModFnWithDict _ _ = False---- (f <<< g $ x) = f (g x)--- (f <<< g) = \x -> f (g x)-inlineFnComposition :: forall m. MonadSupply m => JS -> m JS-inlineFnComposition = everywhereOnJSTopDownM convert where- convert :: JS -> m JS- convert (JSApp s1 (JSApp s2 (JSApp _ (JSApp _ fn [dict']) [x]) [y]) [z])- | isFnCompose dict' fn = return $ JSApp s1 x [JSApp s2 y [z]]- | isFnComposeFlipped dict' fn = return $ JSApp s2 y [JSApp s1 x [z]]- convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y])- | isFnCompose dict' fn = do- arg <- freshName- return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing x [JSApp Nothing y [JSVar Nothing arg]]])- | isFnComposeFlipped dict' fn = do- arg <- freshName- return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing y [JSApp Nothing x [JSVar Nothing arg]]])- convert other = return other- isFnCompose :: JS -> JS -> Bool- isFnCompose dict' fn = isDict semigroupoidFn dict' && isDict fnCompose fn- isFnComposeFlipped :: JS -> JS -> Bool- isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isDict fnComposeFlipped fn- fnCompose :: forall a b. (IsString a, IsString b) => (a, b)- fnCompose = (C.controlSemigroupoid, C.compose)- fnComposeFlipped :: forall a b. (IsString a, IsString b) => (a, b)- fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)--inlineUnsafePartial :: JS -> JS-inlineUnsafePartial = everywhereOnJSTopDown convert where- convert (JSApp ss (JSIndexer _ (JSStringLiteral _ unsafePartial) (JSVar _ partialUnsafe)) [ comp ])- | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe- -- Apply to undefined here, the application should be optimized away- -- if it is safe to do so- = JSApp ss comp [ JSVar ss C.undefined ]- convert other = other--semiringNumber :: forall a b. (IsString a, IsString b) => (a, b)-semiringNumber = (C.dataSemiring, C.semiringNumber)--semiringInt :: forall a b. (IsString a, IsString b) => (a, b)-semiringInt = (C.dataSemiring, C.semiringInt)--ringNumber :: forall a b. (IsString a, IsString b) => (a, b)-ringNumber = (C.dataRing, C.ringNumber)--ringInt :: forall a b. (IsString a, IsString b) => (a, b)-ringInt = (C.dataRing, C.ringInt)--euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)-euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)--euclideanRingInt :: forall a b. (IsString a, IsString b) => (a, b)-euclideanRingInt = (C.dataEuclideanRing, C.euclideanRingInt)--eqNumber :: forall a b. (IsString a, IsString b) => (a, b)-eqNumber = (C.dataEq, C.eqNumber)--eqInt :: forall a b. (IsString a, IsString b) => (a, b)-eqInt = (C.dataEq, C.eqInt)--eqString :: forall a b. (IsString a, IsString b) => (a, b)-eqString = (C.dataEq, C.eqString)--eqChar :: forall a b. (IsString a, IsString b) => (a, b)-eqChar = (C.dataEq, C.eqChar)--eqBoolean :: forall a b. (IsString a, IsString b) => (a, b)-eqBoolean = (C.dataEq, C.eqBoolean)--ordBoolean :: forall a b. (IsString a, IsString b) => (a, b)-ordBoolean = (C.dataOrd, C.ordBoolean)--ordNumber :: forall a b. (IsString a, IsString b) => (a, b)-ordNumber = (C.dataOrd, C.ordNumber)--ordInt :: forall a b. (IsString a, IsString b) => (a, b)-ordInt = (C.dataOrd, C.ordInt)--ordString :: forall a b. (IsString a, IsString b) => (a, b)-ordString = (C.dataOrd, C.ordString)--ordChar :: forall a b. (IsString a, IsString b) => (a, b)-ordChar = (C.dataOrd, C.ordChar)--semigroupString :: forall a b. (IsString a, IsString b) => (a, b)-semigroupString = (C.dataSemigroup, C.semigroupString)--boundedBoolean :: forall a b. (IsString a, IsString b) => (a, b)-boundedBoolean = (C.dataBounded, C.boundedBoolean)--heytingAlgebraBoolean :: forall a b. (IsString a, IsString b) => (a, b)-heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)--semigroupoidFn :: forall a b. (IsString a, IsString b) => (a, b)-semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)--opAdd :: forall a b. (IsString a, IsString b) => (a, b)-opAdd = (C.dataSemiring, C.add)--opMul :: forall a b. (IsString a, IsString b) => (a, b)-opMul = (C.dataSemiring, C.mul)--opEq :: forall a b. (IsString a, IsString b) => (a, b)-opEq = (C.dataEq, C.eq)--opNotEq :: forall a b. (IsString a, IsString b) => (a, b)-opNotEq = (C.dataEq, C.notEq)--opLessThan :: forall a b. (IsString a, IsString b) => (a, b)-opLessThan = (C.dataOrd, C.lessThan)--opLessThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)-opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)--opGreaterThan :: forall a b. (IsString a, IsString b) => (a, b)-opGreaterThan = (C.dataOrd, C.greaterThan)--opGreaterThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)-opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)--opAppend :: forall a b. (IsString a, IsString b) => (a, b)-opAppend = (C.dataSemigroup, C.append)--opSub :: forall a b. (IsString a, IsString b) => (a, b)-opSub = (C.dataRing, C.sub)--opNegate :: forall a b. (IsString a, IsString b) => (a, b)-opNegate = (C.dataRing, C.negate)--opDiv :: forall a b. (IsString a, IsString b) => (a, b)-opDiv = (C.dataEuclideanRing, C.div)--opMod :: forall a b. (IsString a, IsString b) => (a, b)-opMod = (C.dataEuclideanRing, C.mod)--opConj :: forall a b. (IsString a, IsString b) => (a, b)-opConj = (C.dataHeytingAlgebra, C.conj)--opDisj :: forall a b. (IsString a, IsString b) => (a, b)-opDisj = (C.dataHeytingAlgebra, C.disj)--opNot :: forall a b. (IsString a, IsString b) => (a, b)-opNot = (C.dataHeytingAlgebra, C.not)
− src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs
@@ -1,137 +0,0 @@--- |--- This module implements the "Magic Do" optimization, which inlines calls to return--- and bind for the Eff monad, as well as some of its actions.----module Language.PureScript.CodeGen.JS.Optimizer.MagicDo (magicDo) where--import Prelude.Compat--import Data.List (nub)-import Data.Maybe (fromJust, isJust)--import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.CodeGen.JS.Optimizer.Common-import Language.PureScript.Options-import Language.PureScript.PSString (mkString)-import qualified Language.PureScript.Constants as C--magicDo :: Options -> JS -> JS-magicDo opts | optionsNoMagicDo opts = id- | otherwise = inlineST . magicDo'---- |--- Inline type class dictionaries for >>= and return for the Eff monad------ E.g.------ Prelude[">>="](dict)(m1)(function(x) {--- return ...;--- })------ becomes------ function __do {--- var x = m1();--- ...--- }----magicDo' :: JS -> JS-magicDo' = everywhereOnJS undo . everywhereOnJSTopDown convert- where- -- The name of the function block which is added to denote a do block- fnName = "__do"- -- Desugar monomorphic calls to >>= and return for the Eff monad- convert :: JS -> JS- -- Desugar pure & return- convert (JSApp _ (JSApp _ pure' [val]) []) | isPure pure' = val- -- Desugar >>- convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [] (JSBlock s2 js)]) | isBind bind =- JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSApp s2 m [] : map applyReturns js )- -- Desugar >>=- convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [arg] (JSBlock s2 js)]) | isBind bind =- JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSVariableIntroduction s2 arg (Just (JSApp s2 m [])) : map applyReturns js)- -- Desugar untilE- convert (JSApp s1 (JSApp _ f [arg]) []) | isEffFunc C.untilE f =- JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSUnary s1 Not (JSApp s1 arg [])) (JSBlock s1 []), JSReturn s1 $ JSObjectLiteral s1 []])) []- -- Desugar whileE- convert (JSApp _ (JSApp _ (JSApp s1 f [arg1]) [arg2]) []) | isEffFunc C.whileE f =- JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSApp s1 arg1 []) (JSBlock s1 [ JSApp s1 arg2 [] ]), JSReturn s1 $ JSObjectLiteral s1 []])) []- convert other = other- -- Check if an expression represents a monomorphic call to >>= for the Eff monad- isBind (JSApp _ fn [dict]) | isDict (C.eff, C.bindEffDictionary) dict && isBindPoly fn = True- isBind _ = False- -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative- isPure (JSApp _ fn [dict]) | isDict (C.eff, C.applicativeEffDictionary) dict && isPurePoly fn = True- isPure _ = False- -- Check if an expression represents the polymorphic >>= function- isBindPoly = isDict (C.controlBind, C.bind)- -- Check if an expression represents the polymorphic pure or return function- isPurePoly = isDict (C.controlApplicative, C.pure')- -- Check if an expression represents a function in the Eff module- isEffFunc name (JSIndexer _ (JSStringLiteral _ name') (JSVar _ eff)) = eff == C.eff && name == name'- isEffFunc _ _ = False-- -- Remove __do function applications which remain after desugaring- undo :: JS -> JS- undo (JSReturn _ (JSApp _ (JSFunction _ (Just ident) [] body) [])) | ident == fnName = body- undo other = other-- applyReturns :: JS -> JS- applyReturns (JSReturn ss ret) = JSReturn ss (JSApp ss ret [])- applyReturns (JSBlock ss jss) = JSBlock ss (map applyReturns jss)- applyReturns (JSWhile ss cond js) = JSWhile ss cond (applyReturns js)- applyReturns (JSFor ss v lo hi js) = JSFor ss v lo hi (applyReturns js)- applyReturns (JSForIn ss v xs js) = JSForIn ss v xs (applyReturns js)- applyReturns (JSIfElse ss cond t f) = JSIfElse ss cond (applyReturns t) (applyReturns `fmap` f)- applyReturns other = other---- |--- Inline functions in the ST module----inlineST :: JS -> JS-inlineST = everywhereOnJS convertBlock- where- -- Look for runST blocks and inline the STRefs there.- -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then- -- we can be more aggressive about inlining, and actually turn STRefs into local variables.- convertBlock (JSApp _ f [arg]) | isSTFunc C.runST f =- let refs = nub . findSTRefsIn $ arg- usages = findAllSTUsagesIn arg- allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages- localVarsDoNotEscape = all (\r -> length (r `appearingIn` arg) == length (filter (\u -> let v = toVar u in v == Just r) usages)) refs- in everywhereOnJS (convert (allUsagesAreLocalVars && localVarsDoNotEscape)) arg- convertBlock other = other- -- Convert a block in a safe way, preserving object wrappers of references,- -- or in a more aggressive way, turning wrappers into local variables depending on the- -- agg(ressive) parameter.- convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =- JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(mkString C.stRefValue, arg)]])- convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =- if agg then ref else JSIndexer s1 (JSStringLiteral s1 C.stRefValue) ref- convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =- if agg then JSAssignment s1 ref arg else JSAssignment s1 (JSIndexer s1 (JSStringLiteral s1 C.stRefValue) ref) arg- convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [func]) []) | isSTFunc C.modifySTRef f =- if agg then JSAssignment s1 ref (JSApp s1 func [ref]) else JSAssignment s1 (JSIndexer s1 (JSStringLiteral s1 C.stRefValue) ref) (JSApp s1 func [JSIndexer s1 (JSStringLiteral s1 C.stRefValue) ref])- convert _ other = other- -- Check if an expression represents a function in the ST module- isSTFunc name (JSIndexer _ (JSStringLiteral _ name') (JSVar _ st)) = st == C.st && name == name'- isSTFunc _ _ = False- -- Find all ST Refs initialized in this block- findSTRefsIn = everythingOnJS (++) isSTRef- where- isSTRef (JSVariableIntroduction _ ident (Just (JSApp _ (JSApp _ f [_]) []))) | isSTFunc C.newSTRef f = [ident]- isSTRef _ = []- -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef- findAllSTUsagesIn = everythingOnJS (++) isSTUsage- where- isSTUsage (JSApp _ (JSApp _ f [ref]) []) | isSTFunc C.readSTRef f = [ref]- isSTUsage (JSApp _ (JSApp _ (JSApp _ f [ref]) [_]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]- isSTUsage _ = []- -- Find all uses of a variable- appearingIn ref = everythingOnJS (++) isVar- where- isVar e@(JSVar _ v) | v == ref = [e]- isVar _ = []- -- Convert a JS value to a String if it is a JSVar- toVar (JSVar _ v) = Just v- toVar _ = Nothing
− src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs
@@ -1,120 +0,0 @@--- |--- This module implements tail call elimination.----module Language.PureScript.CodeGen.JS.Optimizer.TCO (tco) where--import Prelude.Compat--import Data.Text (Text)-import Data.Monoid ((<>), getAny, Any(..))--import Language.PureScript.Options-import Language.PureScript.CodeGen.JS.AST---- |--- Eliminate tail calls----tco :: Options -> JS -> JS-tco opts | optionsNoTco opts = id- | otherwise = tco'--tco' :: JS -> JS-tco' = everywhereOnJS convert- where- tcoLabel :: Text- tcoLabel = "tco"-- tcoVar :: Text -> Text- tcoVar arg = "__tco_" <> arg-- copyVar :: Text -> Text- copyVar arg = "__copy_" <> arg-- convert :: JS -> JS- convert js@(JSVariableIntroduction ss name (Just fn@JSFunction {})) =- let- (argss, body', replace) = collectAllFunctionArgs [] id fn- in case () of- _ | isTailCall name body' ->- let- allArgs = concat $ reverse argss- in- JSVariableIntroduction ss name (Just (replace (toLoop name allArgs body')))- | otherwise -> js- convert js = js-- collectAllFunctionArgs :: [[Text]] -> (JS -> JS) -> JS -> ([[Text]], JS, JS -> JS)- collectAllFunctionArgs allArgs f (JSFunction s1 ident args (JSBlock s2 (body@(JSReturn _ _):_))) =- collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction s1 ident (map copyVar args) (JSBlock s2 [b]))) body- collectAllFunctionArgs allArgs f (JSFunction ss ident args body@(JSBlock _ _)) =- (args : allArgs, body, f . JSFunction ss ident (map copyVar args))- collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args (JSBlock s3 [body]))) =- collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn s1 (JSFunction s2 ident (map copyVar args) (JSBlock s3 [b])))) body- collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args body@(JSBlock _ _))) =- (args : allArgs, body, f . JSReturn s1 . JSFunction s2 ident (map copyVar args))- collectAllFunctionArgs allArgs f body = (allArgs, body, f)-- isTailCall :: Text -> JS -> Bool- isTailCall ident js =- let- numSelfCalls = everythingOnJS (+) countSelfCalls js- numSelfCallsInTailPosition = everythingOnJS (+) countSelfCallsInTailPosition js- numSelfCallsUnderFunctions = everythingOnJS (+) countSelfCallsUnderFunctions js- numSelfCallWithFnArgs = everythingOnJS (+) countSelfCallsWithFnArgs js- in- numSelfCalls > 0- && numSelfCalls == numSelfCallsInTailPosition- && numSelfCallsUnderFunctions == 0- && numSelfCallWithFnArgs == 0- where- countSelfCalls :: JS -> Int- countSelfCalls (JSApp _ (JSVar _ ident') _) | ident == ident' = 1- countSelfCalls _ = 0-- countSelfCallsInTailPosition :: JS -> Int- countSelfCallsInTailPosition (JSReturn _ ret) | isSelfCall ident ret = 1- countSelfCallsInTailPosition _ = 0-- countSelfCallsUnderFunctions :: JS -> Int- countSelfCallsUnderFunctions (JSFunction _ _ _ js') = everythingOnJS (+) countSelfCalls js'- countSelfCallsUnderFunctions _ = 0-- countSelfCallsWithFnArgs :: JS -> Int- countSelfCallsWithFnArgs = go [] where- go acc (JSVar _ ident')- | ident == ident' && any hasFunction acc = 1- go acc (JSApp _ fn args) = go (args ++ acc) fn- go _ _ = 0-- hasFunction :: JS -> Bool- hasFunction = getAny . everythingOnJS mappend (Any . isFunction)- where- isFunction JSFunction{} = True- isFunction _ = False-- toLoop :: Text -> [Text] -> JS -> JS- toLoop ident allArgs js = JSBlock rootSS $- map (\arg -> JSVariableIntroduction rootSS arg (Just (JSVar rootSS (copyVar arg)))) allArgs ++- [ JSLabel rootSS tcoLabel $ JSWhile rootSS (JSBooleanLiteral rootSS True) (JSBlock rootSS [ everywhereOnJS loopify js ]) ]- where- rootSS = Nothing-- loopify :: JS -> JS- loopify (JSReturn ss ret) | isSelfCall ident ret =- let- allArgumentValues = concat $ collectSelfCallArgs [] ret- in- JSBlock ss $ zipWith (\val arg ->- JSVariableIntroduction ss (tcoVar arg) (Just val)) allArgumentValues allArgs- ++ map (\arg ->- JSAssignment ss (JSVar ss arg) (JSVar ss (tcoVar arg))) allArgs- ++ [ JSContinue ss tcoLabel ]- loopify other = other- collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]- collectSelfCallArgs allArgumentValues (JSApp _ fn args') = collectSelfCallArgs (args' : allArgumentValues) fn- collectSelfCallArgs allArgumentValues _ = allArgumentValues-- isSelfCall :: Text -> JS -> Bool- isSelfCall ident (JSApp _ (JSVar _ ident') _) = ident == ident'- isSelfCall ident (JSApp _ fn _) = isSelfCall ident fn- isSelfCall _ _ = False
− src/Language/PureScript/CodeGen/JS/Optimizer/Unused.hs
@@ -1,35 +0,0 @@--- |--- Removes unused variables----module Language.PureScript.CodeGen.JS.Optimizer.Unused- ( removeCodeAfterReturnStatements- , removeUnusedArg- , removeUndefinedApp- ) where--import Prelude.Compat--import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.CodeGen.JS.Optimizer.Common-import qualified Language.PureScript.Constants as C--removeCodeAfterReturnStatements :: JS -> JS-removeCodeAfterReturnStatements = everywhereOnJS (removeFromBlock go)- where- go :: [JS] -> [JS]- go jss | not (any isJSReturn jss) = jss- | otherwise = let (body, ret : _) = break isJSReturn jss in body ++ [ret]- isJSReturn (JSReturn _ _) = True- isJSReturn _ = False--removeUnusedArg :: JS -> JS-removeUnusedArg = everywhereOnJS convert- where- convert (JSFunction ss name [arg] body) | arg == C.__unused = JSFunction ss name [] body- convert js = js--removeUndefinedApp :: JS -> JS-removeUndefinedApp = everywhereOnJS convert- where- convert (JSApp ss fn [JSVar _ arg]) | arg == C.undefined = JSApp ss fn []- convert js = js
+ src/Language/PureScript/CodeGen/JS/Printer.hs view
@@ -0,0 +1,272 @@+-- | Pretty printer for the JavaScript AST+module Language.PureScript.CodeGen.JS.Printer+ ( prettyPrintJS+ , prettyPrintJSWithSourceMaps+ ) where++import Prelude.Compat++import Control.Arrow ((<+>))+import Control.Monad (forM, mzero)+import Control.Monad.State (StateT, evalStateT)+import Control.PatternArrows+import qualified Control.Arrow as A++import Data.Maybe (fromMaybe)+import Data.Monoid ((<>))+import Data.Text (Text)+import qualified Data.Text as T++import Language.PureScript.AST (SourceSpan(..))+import Language.PureScript.CodeGen.JS.Common+import Language.PureScript.CoreImp.AST+import Language.PureScript.Comments+import Language.PureScript.Crash+import Language.PureScript.Pretty.Common+import Language.PureScript.PSString (PSString, decodeString, prettyPrintStringJS)++-- TODO (Christoph): Get rid of T.unpack / pack++literals :: (Emit gen) => Pattern PrinterState AST gen+literals = mkPattern' match'+ where+ match' :: (Emit gen) => AST -> StateT PrinterState Maybe gen+ match' js = (addMapping' (getSourceSpan js) <>) <$> match js++ match :: (Emit gen) => AST -> StateT PrinterState Maybe gen+ match (NumericLiteral _ n) = return $ emit $ T.pack $ either show show n+ match (StringLiteral _ s) = return $ emit $ prettyPrintStringJS s+ match (BooleanLiteral _ True) = return $ emit "true"+ match (BooleanLiteral _ False) = return $ emit "false"+ match (ArrayLiteral _ xs) = mconcat <$> sequence+ [ return $ emit "[ "+ , intercalate (emit ", ") <$> forM xs prettyPrintJS'+ , return $ emit " ]"+ ]+ match (ObjectLiteral _ []) = return $ emit "{}"+ match (ObjectLiteral _ ps) = mconcat <$> sequence+ [ return $ emit "{\n"+ , withIndent $ do+ jss <- forM ps $ \(key, value) -> fmap ((objectPropertyToString key <> emit ": ") <>) . prettyPrintJS' $ value+ indentString <- currentIndent+ return $ intercalate (emit ", \n") $ map (indentString <>) jss+ , return $ emit "\n"+ , currentIndent+ , return $ emit "}"+ ]+ where+ objectPropertyToString :: (Emit gen) => PSString -> gen+ objectPropertyToString s =+ emit $ case decodeString s of+ Just s' | not (identNeedsEscaping s') ->+ s'+ _ ->+ prettyPrintStringJS s+ match (Block _ sts) = mconcat <$> sequence+ [ return $ emit "{\n"+ , withIndent $ prettyStatements sts+ , return $ emit "\n"+ , currentIndent+ , return $ emit "}"+ ]+ match (Var _ ident) = return $ emit ident+ match (VariableIntroduction _ ident value) = mconcat <$> sequence+ [ return $ emit $ "var " <> ident+ , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintJS') value+ ]+ match (Assignment _ target value) = mconcat <$> sequence+ [ prettyPrintJS' target+ , return $ emit " = "+ , prettyPrintJS' value+ ]+ match (While _ cond sts) = mconcat <$> sequence+ [ return $ emit "while ("+ , prettyPrintJS' cond+ , return $ emit ") "+ , prettyPrintJS' sts+ ]+ match (For _ ident start end sts) = mconcat <$> sequence+ [ return $ emit $ "for (var " <> ident <> " = "+ , prettyPrintJS' start+ , return $ emit $ "; " <> ident <> " < "+ , prettyPrintJS' end+ , return $ emit $ "; " <> ident <> "++) "+ , prettyPrintJS' sts+ ]+ match (ForIn _ ident obj sts) = mconcat <$> sequence+ [ return $ emit $ "for (var " <> ident <> " in "+ , prettyPrintJS' obj+ , return $ emit ") "+ , prettyPrintJS' sts+ ]+ match (IfElse _ cond thens elses) = mconcat <$> sequence+ [ return $ emit "if ("+ , prettyPrintJS' cond+ , return $ emit ") "+ , prettyPrintJS' thens+ , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintJS') elses+ ]+ match (Return _ value) = mconcat <$> sequence+ [ return $ emit "return "+ , prettyPrintJS' value+ ]+ match (ReturnNoResult _) = return $ emit "return"+ match (Throw _ value) = mconcat <$> sequence+ [ return $ emit "throw "+ , prettyPrintJS' value+ ]+ match (Comment _ com js) = mconcat <$> sequence+ [ mconcat <$> forM com comment+ , prettyPrintJS' js+ ]+ match _ = mzero++ comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen+ comment (LineComment com) = fmap mconcat $ sequence $+ [ return $ emit "\n"+ , currentIndent+ , return $ emit "//" <> emit com <> emit "\n"+ ]+ comment (BlockComment com) = fmap mconcat $ sequence $+ [ return $ emit "\n"+ , currentIndent+ , return $ emit "/**\n"+ ] +++ map asLine (T.lines com) +++ [ currentIndent+ , return $ emit " */\n"+ , currentIndent+ ]+ where+ asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen+ asLine s = do+ i <- currentIndent+ return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"++ removeComments :: Text -> Text+ removeComments t =+ case T.stripPrefix "*/" t of+ Just rest -> removeComments rest+ Nothing -> case T.uncons t of+ Just (x, xs) -> x `T.cons` removeComments xs+ Nothing -> ""++accessor :: Pattern PrinterState AST (Text, AST)+accessor = mkPattern match+ where+ match (Indexer _ (StringLiteral _ prop) val) =+ case decodeString prop of+ Just s | not (identNeedsEscaping s) -> Just (s, val)+ _ -> Nothing+ match _ = Nothing++indexer :: (Emit gen) => Pattern PrinterState AST (gen, AST)+indexer = mkPattern' match+ where+ match (Indexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val+ match _ = mzero++lam :: Pattern PrinterState AST ((Maybe Text, [Text], Maybe SourceSpan), AST)+lam = mkPattern match+ where+ match (Function ss name args ret) = Just ((name, args, ss), ret)+ match _ = Nothing++app :: (Emit gen) => Pattern PrinterState AST (gen, AST)+app = mkPattern' match+ where+ match (App _ val args) = do+ jss <- traverse prettyPrintJS' args+ return (intercalate (emit ", ") jss, val)+ match _ = mzero++instanceOf :: Pattern PrinterState AST (AST, AST)+instanceOf = mkPattern match+ where+ match (InstanceOf _ val ty) = Just (val, ty)+ match _ = Nothing++unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen+unary' op mkStr = Wrap match (<>)+ where+ match :: (Emit gen) => Pattern PrinterState AST (gen, AST)+ match = mkPattern match'+ where+ match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)+ match' _ = Nothing++unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen+unary op str = unary' op (const str)++negateOperator :: (Emit gen) => Operator PrinterState AST gen+negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")+ where+ isNegate (Unary _ Negate _) = True+ isNegate _ = False++binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen+binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)+ where+ match :: Pattern PrinterState AST (AST, AST)+ match = mkPattern match'+ where+ match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)+ match' _ = Nothing++prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen+prettyStatements sts = do+ jss <- forM sts prettyPrintJS'+ indentString <- currentIndent+ return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) jss++-- | Generate a pretty-printed string representing a collection of JavaScript expressions at the same indentation level+prettyPrintJSWithSourceMaps :: [AST] -> (Text, [SMap])+prettyPrintJSWithSourceMaps js =+ let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) js+ in (s, mp)++prettyPrintJS :: [AST] -> Text+prettyPrintJS = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements++-- | Generate an indented, pretty-printed string representing a JavaScript expression+prettyPrintJS' :: (Emit gen) => AST -> StateT PrinterState Maybe gen+prettyPrintJS' = A.runKleisli $ runPattern matchValue+ where+ matchValue :: (Emit gen) => Pattern PrinterState AST gen+ matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)+ operators :: (Emit gen) => OperatorTable PrinterState AST gen+ operators =+ OperatorTable [ [ Wrap indexer $ \index val -> val <> emit "[" <> index <> emit "]" ]+ , [ Wrap accessor $ \prop val -> val <> emit "." <> emit prop ]+ , [ Wrap app $ \args val -> val <> emit "(" <> args <> emit ")" ]+ , [ unary New "new " ]+ , [ Wrap lam $ \(name, args, ss) ret -> addMapping' ss <>+ emit ("function "+ <> fromMaybe "" name+ <> "(" <> intercalate ", " args <> ") ")+ <> ret ]+ , [ unary Not "!"+ , unary BitwiseNot "~"+ , unary Positive "+"+ , negateOperator ]+ , [ binary Multiply "*"+ , binary Divide "/"+ , binary Modulus "%" ]+ , [ binary Add "+"+ , binary Subtract "-" ]+ , [ binary ShiftLeft "<<"+ , binary ShiftRight ">>"+ , binary ZeroFillShiftRight ">>>" ]+ , [ binary LessThan "<"+ , binary LessThanOrEqualTo "<="+ , binary GreaterThan ">"+ , binary GreaterThanOrEqualTo ">="+ , AssocR instanceOf $ \v1 v2 -> v1 <> emit " instanceof " <> v2 ]+ , [ binary EqualTo "==="+ , binary NotEqualTo "!==" ]+ , [ binary BitwiseAnd "&" ]+ , [ binary BitwiseXor "^" ]+ , [ binary BitwiseOr "|" ]+ , [ binary And "&&" ]+ , [ binary Or "||" ]+ ]
src/Language/PureScript/Constants.hs view
@@ -34,6 +34,12 @@ bind :: forall a. (IsString a) => a bind = "bind" +discard :: forall a. (IsString a) => a+discard = "discard"++pattern Discard :: Qualified (ProperName 'ClassName)+pattern Discard = Qualified (Just ControlBind) (ProperName "Discard")+ (+) :: forall a. (IsString a) => a (+) = "+" @@ -234,6 +240,9 @@ bindEffDictionary :: forall a. (IsString a) => a bindEffDictionary = "bindEff" +discardUnitDictionary :: forall a. (IsString a) => a+discardUnitDictionary = "discardUnit"+ semiringNumber :: forall a. (IsString a) => a semiringNumber = "semiringNumber" @@ -372,20 +381,17 @@ pattern Warn :: Qualified (ProperName 'ClassName) pattern Warn = Qualified (Just Prim) (ProperName "Warn") +pattern Union :: Qualified (ProperName 'ClassName)+pattern Union = Qualified (Just Prim) (ProperName "Union")+ typ :: forall a. (IsString a) => a typ = "Type" -effect :: forall a. (IsString a) => a-effect = "Effect"- symbol :: forall a. (IsString a) => a symbol = "Symbol" -- Code Generation -__superclass_ :: forall a. (IsString a) => a-__superclass_ = "__superclass_"- __unused :: forall a. (IsString a) => a __unused = "__unused" @@ -411,6 +417,9 @@ controlSemigroupoid :: forall a. (IsString a) => a controlSemigroupoid = "Control_Semigroupoid"++pattern ControlBind :: ModuleName+pattern ControlBind = ModuleName [ProperName "Control", ProperName "Bind"] controlBind :: forall a. (IsString a) => a controlBind = "Control_Bind"
src/Language/PureScript/CoreFn/Desugar.hs view
@@ -1,19 +1,20 @@ module Language.PureScript.CoreFn.Desugar (moduleToCoreFn) where import Prelude.Compat+import Protolude (ordNub) -import Control.Arrow (second, (***))+import Control.Arrow (second) import Data.Function (on)-import Data.List (sort, sortBy, nub)+import Data.List (sort, sortBy) import Data.Maybe (mapMaybe)+import Data.Tuple (swap) import qualified Data.Map as M import Language.PureScript.AST.Literals import Language.PureScript.AST.SourcePos import Language.PureScript.AST.Traversals import Language.PureScript.Comments-import qualified Language.PureScript.Constants as C import Language.PureScript.CoreFn.Ann import Language.PureScript.CoreFn.Binders import Language.PureScript.CoreFn.Expr@@ -27,38 +28,38 @@ import Language.PureScript.PSString (mkString) import qualified Language.PureScript.AST as A --- |--- Desugars a module from AST to CoreFn representation.---+-- | Desugars a module from AST to CoreFn representation. moduleToCoreFn :: Environment -> A.Module -> Module Ann moduleToCoreFn _ (A.Module _ _ _ _ Nothing) = internalError "Module exports were not elaborated before moduleToCoreFn" moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) = let imports = mapMaybe importToCoreFn decls ++ findQualModules decls- imports' = nub $ filter (keepImp imports) imports-- TODO could be more efficient- exps' = nub $ concatMap exportToCoreFn exps- externs = nub $ mapMaybe externToCoreFn decls+ imports' = keepPositionedImports imports+ exps' = ordNub $ concatMap exportToCoreFn exps+ externs = ordNub $ mapMaybe externToCoreFn decls decls' = concatMap (declToCoreFn Nothing []) decls in Module coms mn imports' exps' externs decls' where - -- Remove duplicate imports favoring the one containing sourcespan info- keepImp :: [(Ann, ModuleName)] -> (Ann, ModuleName) -> Bool- keepImp imps (a, i) = hasSS a || not (any hasDup imps)+ -- | Remove duplicate imports favoring the ones containing source span+ -- information+ keepPositionedImports :: [(Ann, ModuleName)] -> [(Ann, ModuleName)]+ keepPositionedImports =+ map swap . M.toList . M.fromListWith preferSSpan . map swap where- hasDup (a', i') = i == i' && hasSS a'+ preferSSpan x y+ | hasSS x = x+ | otherwise = y - hasSS :: Ann -> Bool- hasSS (Just _, _, _, _) = True- hasSS _ = False+ hasSS :: Ann -> Bool+ hasSS (Just _, _, _, _) = True+ hasSS _ = False ssA :: Maybe SourceSpan -> Ann ssA ss = (ss, [], Nothing, Nothing) - -- |- -- Desugars member declarations from AST to CoreFn representation.- --+ -- | Desugars member declarations from AST to CoreFn representation. declToCoreFn :: Maybe SourceSpan -> [Comment] -> A.Declaration -> [Bind Ann] declToCoreFn ss com (A.DataDeclaration Newtype _ _ [(ctor, _)]) = [NonRec (ssA ss) (properToIdent ctor) $@@ -70,7 +71,7 @@ let (_, _, _, fields) = lookupConstructor env (Qualified (Just mn) ctor) in NonRec (ssA ss) (properToIdent ctor) $ Constructor (ss, com, Nothing, Nothing) tyName ctor fields declToCoreFn ss _ (A.DataBindingGroupDeclaration ds) = concatMap (declToCoreFn ss []) ds- declToCoreFn ss com (A.ValueDeclaration name _ _ (Right e)) =+ declToCoreFn ss com (A.ValueDeclaration name _ _ [A.MkUnguarded e]) = [NonRec (ssA ss) name (exprToCoreFn ss com Nothing e)] declToCoreFn ss _ (A.BindingGroupDeclaration ds) = [Rec $ map (\(name, _, e) -> ((ssA ss, name), exprToCoreFn ss [] Nothing e)) ds]@@ -80,9 +81,7 @@ declToCoreFn (Just ss) (com ++ com1) d declToCoreFn _ _ _ = [] - -- |- -- Desugars expressions from AST to CoreFn representation.- --+ -- | Desugars expressions from AST to CoreFn representation. exprToCoreFn :: Maybe SourceSpan -> [Comment] -> Maybe Type -> A.Expr -> Expr Ann exprToCoreFn ss com ty (A.Literal lit) = Literal (ss, com, ty, Nothing) (fmap (exprToCoreFn ss com Nothing) lit)@@ -90,7 +89,7 @@ Accessor (ss, com, ty, Nothing) name (exprToCoreFn ss [] Nothing v) exprToCoreFn ss com ty (A.ObjectUpdate obj vs) = ObjectUpdate (ss, com, ty, Nothing) (exprToCoreFn ss [] Nothing obj) $ map (second (exprToCoreFn ss [] Nothing)) vs- exprToCoreFn ss com ty (A.Abs (Left name) v) =+ exprToCoreFn ss com ty (A.Abs (A.VarBinder name) v) = Abs (ss, com, ty, Nothing) name (exprToCoreFn ss [] Nothing v) exprToCoreFn _ _ _ (A.Abs _ _) = internalError "Abs with Binder argument was not desugared before exprToCoreFn mn"@@ -102,7 +101,7 @@ Case (ss, com, ty, Nothing) [exprToCoreFn ss [] Nothing v1] [ CaseAlternative [LiteralBinder nullAnn $ BooleanLiteral True] (Right $ exprToCoreFn Nothing [] Nothing v2)- , CaseAlternative [LiteralBinder nullAnn $ BooleanLiteral False]+ , CaseAlternative [NullBinder nullAnn] (Right $ exprToCoreFn Nothing [] Nothing v3) ] exprToCoreFn ss com ty (A.Constructor name) = Var (ss, com, ty, Just $ getConstructorMeta name) $ fmap properToIdent name@@ -126,19 +125,23 @@ exprToCoreFn _ _ _ e = error $ "Unexpected value in exprToCoreFn mn: " ++ show e - -- |- -- Desugars case alternatives from AST to CoreFn representation.- --+ -- | Desugars case alternatives from AST to CoreFn representation. altToCoreFn :: Maybe SourceSpan -> A.CaseAlternative -> CaseAlternative Ann altToCoreFn ss (A.CaseAlternative bs vs) = CaseAlternative (map (binderToCoreFn ss []) bs) (go vs) where- go :: Either [(A.Guard, A.Expr)] A.Expr -> Either [(Guard Ann, Expr Ann)] (Expr Ann)- go (Left ges) = Left $ map (exprToCoreFn ss [] Nothing *** exprToCoreFn ss [] Nothing) ges- go (Right e) = Right (exprToCoreFn ss [] Nothing e)+ go :: [A.GuardedExpr] -> Either [(Guard Ann, Expr Ann)] (Expr Ann)+ go [A.MkUnguarded e]+ = Right (exprToCoreFn ss [] Nothing e)+ go gs+ = Left [ (exprToCoreFn ss [] Nothing cond, exprToCoreFn ss [] Nothing e)+ | A.GuardedExpr g e <- gs+ , let cond = guardToExpr g+ ] - -- |- -- Desugars case binders from AST to CoreFn representation.- --+ guardToExpr [A.ConditionGuard cond] = cond+ guardToExpr _ = internalError "Guard not correctly desugared"++ -- | Desugars case binders from AST to CoreFn representation. binderToCoreFn :: Maybe SourceSpan -> [Comment] -> A.Binder -> Binder Ann binderToCoreFn ss com (A.LiteralBinder lit) = LiteralBinder (ss, com, Nothing, Nothing) (fmap (binderToCoreFn ss com) lit)@@ -162,18 +165,14 @@ binderToCoreFn _ _ A.ParensInBinder{} = internalError "ParensInBinder should have been desugared before binderToCoreFn" - -- |- -- Gets metadata for values.- --+ -- | Gets metadata for values. getValueMeta :: Qualified Ident -> Maybe Meta getValueMeta name = case lookupValue env name of Just (_, External, _) -> Just IsForeign _ -> Nothing - -- |- -- Gets metadata for data constructors.- --+ -- | Gets metadata for data constructors. getConstructorMeta :: Qualified (ProperName 'ConstructorName) -> Meta getConstructorMeta ctor = case lookupConstructor env ctor of@@ -194,11 +193,9 @@ typeConstructor (Qualified (Just mn') _, (_, tyCtor, _, _)) = (mn', tyCtor) typeConstructor _ = internalError "Invalid argument to typeConstructor" --- |--- Find module names from qualified references to values. This is used to+-- | Find module names from qualified references to values. This is used to -- ensure instances are imported from any module that is referenced by the -- current module, not just from those that are imported explicitly (#667).--- findQualModules :: [A.Declaration] -> [(Ann, ModuleName)] findQualModules decls = let (f, _, _, _, _) = everythingOnValues (++) fqDecls fqValues fqBinders (const []) (const [])@@ -213,11 +210,10 @@ fqValues :: A.Expr -> [ModuleName] fqValues (A.Var q) = getQual' q fqValues (A.Constructor q) = getQual' q- -- IsSymbol instances for literal symbols are automatically solved and the type- -- class dictionaries are built inline instead of having a named instance defined- -- and imported. We therefore need to import the IsSymbol constructor from- -- Data.Symbol if it hasn't already been imported.- fqValues (A.TypeClassDictionaryConstructorApp C.IsSymbol _) = getQual' C.IsSymbol+ -- Some instances are automatically solved and have their class dictionaries+ -- built inline instead of having a named instance defined and imported.+ -- We therefore need to import these constructors if they aren't already.+ fqValues (A.TypeClassDictionaryConstructorApp c _) = getQual' c fqValues _ = [] fqBinders :: A.Binder -> [ModuleName]@@ -227,28 +223,22 @@ getQual' :: Qualified a -> [ModuleName] getQual' = maybe [] return . getQual --- |--- Desugars import declarations from AST to CoreFn representation.---+-- | Desugars import declarations from AST to CoreFn representation. importToCoreFn :: A.Declaration -> Maybe (Ann, ModuleName) importToCoreFn (A.ImportDeclaration name _ _) = Just (nullAnn, name) importToCoreFn (A.PositionedDeclaration ss _ d) = ((,) (Just ss, [], Nothing, Nothing) . snd) <$> importToCoreFn d importToCoreFn _ = Nothing --- |--- Desugars foreign declarations from AST to CoreFn representation.---+-- | Desugars foreign declarations from AST to CoreFn representation. externToCoreFn :: A.Declaration -> Maybe ForeignDecl externToCoreFn (A.ExternDeclaration name ty) = Just (name, ty) externToCoreFn (A.PositionedDeclaration _ _ d) = externToCoreFn d externToCoreFn _ = Nothing --- |--- Desugars export declarations references from AST to CoreFn representation.+-- | Desugars export declarations references from AST to CoreFn representation. -- CoreFn modules only export values, so all data constructors, class -- constructor, instances and values are flattened into one list.--- exportToCoreFn :: A.DeclarationRef -> [Ident] exportToCoreFn (A.TypeRef _ (Just dctors)) = map properToIdent dctors exportToCoreFn (A.ValueRef name) = [name]@@ -257,11 +247,9 @@ exportToCoreFn (A.PositionedDeclarationRef _ _ d) = exportToCoreFn d exportToCoreFn _ = [] --- |--- Makes a typeclass dictionary constructor function. The returned expression+-- | Makes a typeclass dictionary constructor function. The returned expression -- is a function that accepts the superclass instances and member -- implementations and returns a record for the instance dictionary.--- mkTypeClassConstructor :: Maybe SourceSpan -> [Comment] -> [Constraint] -> [A.Declaration] -> Expr Ann mkTypeClassConstructor ss com [] [] = Literal (ss, com, Nothing, Just IsTypeClassConstructor) (ObjectLiteral []) mkTypeClassConstructor ss com supers members =@@ -272,8 +260,6 @@ (Ident a) (foldr (Abs nullAnn . Ident) dict as) --- |--- Converts a ProperName to an Ident.---+-- | Converts a ProperName to an Ident. properToIdent :: ProperName a -> Ident properToIdent = Ident . runProperName
src/Language/PureScript/CoreFn/Meta.hs view
@@ -26,7 +26,7 @@ -- | -- The contained reference is for a foreign member --- | IsForeign deriving (Show, Eq)+ | IsForeign deriving (Show, Eq, Ord) -- | -- Data constructor metadata@@ -39,4 +39,4 @@ -- | -- The constructor is for a type with multiple construcors --- | SumType deriving (Show, Eq)+ | SumType deriving (Show, Eq, Ord)
+ src/Language/PureScript/CoreImp.hs view
@@ -0,0 +1,13 @@+-- | The imperative core language+module Language.PureScript.CoreImp (+ module C+) where++import Language.PureScript.CoreImp.AST as C+import Language.PureScript.CoreImp.Optimizer as C+import Language.PureScript.CoreImp.Optimizer.Blocks as C+import Language.PureScript.CoreImp.Optimizer.Common as C+import Language.PureScript.CoreImp.Optimizer.Inliner as C+import Language.PureScript.CoreImp.Optimizer.MagicDo as C+import Language.PureScript.CoreImp.Optimizer.TCO as C+import Language.PureScript.CoreImp.Optimizer.Unused as C
+ src/Language/PureScript/CoreImp/AST.hs view
@@ -0,0 +1,224 @@+-- | Data types for the imperative core AST+module Language.PureScript.CoreImp.AST where++import Prelude.Compat++import Control.Monad ((>=>))+import Control.Monad.Identity (Identity(..), runIdentity)+import Data.Text (Text)++import Language.PureScript.AST (SourceSpan(..))+import Language.PureScript.Comments+import Language.PureScript.PSString (PSString)+import Language.PureScript.Traversals++-- | Built-in unary operators+data UnaryOperator+ = Negate+ | Not+ | BitwiseNot+ | Positive+ | New+ deriving (Show, Eq)++-- | Built-in binary operators+data BinaryOperator+ = Add+ | Subtract+ | Multiply+ | Divide+ | Modulus+ | EqualTo+ | NotEqualTo+ | LessThan+ | LessThanOrEqualTo+ | GreaterThan+ | GreaterThanOrEqualTo+ | And+ | Or+ | BitwiseAnd+ | BitwiseOr+ | BitwiseXor+ | ShiftLeft+ | ShiftRight+ | ZeroFillShiftRight+ deriving (Show, Eq)++-- | Data type for simplified JavaScript expressions+data AST+ = NumericLiteral (Maybe SourceSpan) (Either Integer Double)+ -- ^ A numeric literal+ | StringLiteral (Maybe SourceSpan) PSString+ -- ^ A string literal+ | BooleanLiteral (Maybe SourceSpan) Bool+ -- ^ A boolean literal+ | Unary (Maybe SourceSpan) UnaryOperator AST+ -- ^ A unary operator application+ | Binary (Maybe SourceSpan) BinaryOperator AST AST+ -- ^ A binary operator application+ | ArrayLiteral (Maybe SourceSpan) [AST]+ -- ^ An array literal+ | Indexer (Maybe SourceSpan) AST AST+ -- ^ An array indexer expression+ | ObjectLiteral (Maybe SourceSpan) [(PSString, AST)]+ -- ^ An object literal+ | Function (Maybe SourceSpan) (Maybe Text) [Text] AST+ -- ^ A function introduction (optional name, arguments, body)+ | App (Maybe SourceSpan) AST [AST]+ -- ^ Function application+ | Var (Maybe SourceSpan) Text+ -- ^ Variable+ | Block (Maybe SourceSpan) [AST]+ -- ^ A block of expressions in braces+ | VariableIntroduction (Maybe SourceSpan) Text (Maybe AST)+ -- ^ A variable introduction and optional initialization+ | Assignment (Maybe SourceSpan) AST AST+ -- ^ A variable assignment+ | While (Maybe SourceSpan) AST AST+ -- ^ While loop+ | For (Maybe SourceSpan) Text AST AST AST+ -- ^ For loop+ | ForIn (Maybe SourceSpan) Text AST AST+ -- ^ ForIn loop+ | IfElse (Maybe SourceSpan) AST AST (Maybe AST)+ -- ^ If-then-else statement+ | Return (Maybe SourceSpan) AST+ -- ^ Return statement+ | ReturnNoResult (Maybe SourceSpan)+ -- ^ Return statement with no return value+ | Throw (Maybe SourceSpan) AST+ -- ^ Throw statement+ | InstanceOf (Maybe SourceSpan) AST AST+ -- ^ instanceof check+ | Comment (Maybe SourceSpan) [Comment] AST+ -- ^ Commented JavaScript+ deriving (Show, Eq)++withSourceSpan :: SourceSpan -> AST -> AST+withSourceSpan withSpan = go where+ ss :: Maybe SourceSpan+ ss = Just withSpan++ go :: AST -> AST+ go (NumericLiteral _ n) = NumericLiteral ss n+ go (StringLiteral _ s) = StringLiteral ss s+ go (BooleanLiteral _ b) = BooleanLiteral ss b+ go (Unary _ op j) = Unary ss op j+ go (Binary _ op j1 j2) = Binary ss op j1 j2+ go (ArrayLiteral _ js) = ArrayLiteral ss js+ go (Indexer _ j1 j2) = Indexer ss j1 j2+ go (ObjectLiteral _ js) = ObjectLiteral ss js+ go (Function _ name args j) = Function ss name args j+ go (App _ j js) = App ss j js+ go (Var _ s) = Var ss s+ go (Block _ js) = Block ss js+ go (VariableIntroduction _ name j) = VariableIntroduction ss name j+ go (Assignment _ j1 j2) = Assignment ss j1 j2+ go (While _ j1 j2) = While ss j1 j2+ go (For _ name j1 j2 j3) = For ss name j1 j2 j3+ go (ForIn _ name j1 j2) = ForIn ss name j1 j2+ go (IfElse _ j1 j2 j3) = IfElse ss j1 j2 j3+ go (Return _ js) = Return ss js+ go (ReturnNoResult _) = ReturnNoResult ss+ go (Throw _ js) = Throw ss js+ go (InstanceOf _ j1 j2) = InstanceOf ss j1 j2+ go (Comment _ com j) = Comment ss com j++getSourceSpan :: AST -> Maybe SourceSpan+getSourceSpan = go where+ go :: AST -> Maybe SourceSpan+ go (NumericLiteral ss _) = ss+ go (StringLiteral ss _) = ss+ go (BooleanLiteral ss _) = ss+ go (Unary ss _ _) = ss+ go (Binary ss _ _ _) = ss+ go (ArrayLiteral ss _) = ss+ go (Indexer ss _ _) = ss+ go (ObjectLiteral ss _) = ss+ go (Function ss _ _ _) = ss+ go (App ss _ _) = ss+ go (Var ss _) = ss+ go (Block ss _) = ss+ go (VariableIntroduction ss _ _) = ss+ go (Assignment ss _ _) = ss+ go (While ss _ _) = ss+ go (For ss _ _ _ _) = ss+ go (ForIn ss _ _ _) = ss+ go (IfElse ss _ _ _) = ss+ go (Return ss _) = ss+ go (ReturnNoResult ss) = ss+ go (Throw ss _) = ss+ go (InstanceOf ss _ _) = ss+ go (Comment ss _ _) = ss++everywhere :: (AST -> AST) -> AST -> AST+everywhere f = go where+ go :: AST -> AST+ go (Unary ss op j) = f (Unary ss op (go j))+ go (Binary ss op j1 j2) = f (Binary ss op (go j1) (go j2))+ go (ArrayLiteral ss js) = f (ArrayLiteral ss (map go js))+ go (Indexer ss j1 j2) = f (Indexer ss (go j1) (go j2))+ go (ObjectLiteral ss js) = f (ObjectLiteral ss (map (fmap go) js))+ go (Function ss name args j) = f (Function ss name args (go j))+ go (App ss j js) = f (App ss (go j) (map go js))+ go (Block ss js) = f (Block ss (map go js))+ go (VariableIntroduction ss name j) = f (VariableIntroduction ss name (fmap go j))+ go (Assignment ss j1 j2) = f (Assignment ss (go j1) (go j2))+ go (While ss j1 j2) = f (While ss (go j1) (go j2))+ go (For ss name j1 j2 j3) = f (For ss name (go j1) (go j2) (go j3))+ go (ForIn ss name j1 j2) = f (ForIn ss name (go j1) (go j2))+ go (IfElse ss j1 j2 j3) = f (IfElse ss (go j1) (go j2) (fmap go j3))+ go (Return ss js) = f (Return ss (go js))+ go (Throw ss js) = f (Throw ss (go js))+ go (InstanceOf ss j1 j2) = f (InstanceOf ss (go j1) (go j2))+ go (Comment ss com j) = f (Comment ss com (go j))+ go other = f other++everywhereTopDown :: (AST -> AST) -> AST -> AST+everywhereTopDown f = runIdentity . everywhereTopDownM (Identity . f)++everywhereTopDownM :: (Monad m) => (AST -> m AST) -> AST -> m AST+everywhereTopDownM f = f >=> go where+ f' = f >=> go+ go (Unary ss op j) = Unary ss op <$> f' j+ go (Binary ss op j1 j2) = Binary ss op <$> f' j1 <*> f' j2+ go (ArrayLiteral ss js) = ArrayLiteral ss <$> traverse f' js+ go (Indexer ss j1 j2) = Indexer ss <$> f' j1 <*> f' j2+ go (ObjectLiteral ss js) = ObjectLiteral ss <$> traverse (sndM f') js+ go (Function ss name args j) = Function ss name args <$> f' j+ go (App ss j js) = App ss <$> f' j <*> traverse f' js+ go (Block ss js) = Block ss <$> traverse f' js+ go (VariableIntroduction ss name j) = VariableIntroduction ss name <$> traverse f' j+ go (Assignment ss j1 j2) = Assignment ss <$> f' j1 <*> f' j2+ go (While ss j1 j2) = While ss <$> f' j1 <*> f' j2+ go (For ss name j1 j2 j3) = For ss name <$> f' j1 <*> f' j2 <*> f' j3+ go (ForIn ss name j1 j2) = ForIn ss name <$> f' j1 <*> f' j2+ go (IfElse ss j1 j2 j3) = IfElse ss <$> f' j1 <*> f' j2 <*> traverse f' j3+ go (Return ss j) = Return ss <$> f' j+ go (Throw ss j) = Throw ss <$> f' j+ go (InstanceOf ss j1 j2) = InstanceOf ss <$> f' j1 <*> f' j2+ go (Comment ss com j) = Comment ss com <$> f' j+ go other = f other++everything :: (r -> r -> r) -> (AST -> r) -> AST -> r+everything (<>) f = go where+ go j@(Unary _ _ j1) = f j <> go j1+ go j@(Binary _ _ j1 j2) = f j <> go j1 <> go j2+ go j@(ArrayLiteral _ js) = foldl (<>) (f j) (map go js)+ go j@(Indexer _ j1 j2) = f j <> go j1 <> go j2+ go j@(ObjectLiteral _ js) = foldl (<>) (f j) (map (go . snd) js)+ go j@(Function _ _ _ j1) = f j <> go j1+ go j@(App _ j1 js) = foldl (<>) (f j <> go j1) (map go js)+ go j@(Block _ js) = foldl (<>) (f j) (map go js)+ go j@(VariableIntroduction _ _ (Just j1)) = f j <> go j1+ go j@(Assignment _ j1 j2) = f j <> go j1 <> go j2+ go j@(While _ j1 j2) = f j <> go j1 <> go j2+ go j@(For _ _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3+ go j@(ForIn _ _ j1 j2) = f j <> go j1 <> go j2+ go j@(IfElse _ j1 j2 Nothing) = f j <> go j1 <> go j2+ go j@(IfElse _ j1 j2 (Just j3)) = f j <> go j1 <> go j2 <> go j3+ go j@(Return _ j1) = f j <> go j1+ go j@(Throw _ j1) = f j <> go j1+ go j@(InstanceOf _ j1 j2) = f j <> go j1 <> go j2+ go j@(Comment _ _ j1) = f j <> go j1+ go other = f other
+ src/Language/PureScript/CoreImp/Optimizer.hs view
@@ -0,0 +1,60 @@+-- | This module optimizes code in the simplified-JavaScript intermediate representation.+--+-- The following optimizations are supported:+--+-- * Collapsing nested blocks+--+-- * Tail call elimination+--+-- * Inlining of (>>=) and ret for the Eff monad+--+-- * Removal of unnecessary thunks+--+-- * Eta conversion+--+-- * Inlining variables+--+-- * Inline Prelude.($), Prelude.(#), Prelude.(++), Prelude.(!!)+--+-- * Inlining primitive JavaScript operators+module Language.PureScript.CoreImp.Optimizer (optimize) where++import Prelude.Compat++import Control.Monad.Supply.Class (MonadSupply)+import Language.PureScript.CoreImp.AST+import Language.PureScript.CoreImp.Optimizer.Blocks+import Language.PureScript.CoreImp.Optimizer.Common+import Language.PureScript.CoreImp.Optimizer.Inliner+import Language.PureScript.CoreImp.Optimizer.MagicDo+import Language.PureScript.CoreImp.Optimizer.TCO+import Language.PureScript.CoreImp.Optimizer.Unused++-- | Apply a series of optimizer passes to simplified JavaScript code+optimize :: MonadSupply m => AST -> m AST+optimize js = do+ js' <- untilFixedPoint (inlineFnComposition . inlineUnsafePartial . tidyUp . applyAll+ [ inlineCommonValues+ , inlineCommonOperators+ ]) js+ untilFixedPoint (return . tidyUp) . tco . magicDo $ js'+ where+ tidyUp :: AST -> AST+ tidyUp = applyAll+ [ collapseNestedBlocks+ , collapseNestedIfs+ , removeCodeAfterReturnStatements+ , removeUnusedArg+ , removeUndefinedApp+ , unThunk+ , etaConvert+ , evaluateIifes+ , inlineVariables+ ]++untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a+untilFixedPoint f = go+ where+ go a = do+ a' <- f a+ if a' == a then return a' else go a'
+ src/Language/PureScript/CoreImp/Optimizer/Blocks.hs view
@@ -0,0 +1,28 @@+-- | Optimizer steps for simplifying JavaScript blocks+module Language.PureScript.CoreImp.Optimizer.Blocks+ ( collapseNestedBlocks+ , collapseNestedIfs+ ) where++import Prelude.Compat++import Language.PureScript.CoreImp.AST++-- | Collapse blocks which appear nested directly below another block+collapseNestedBlocks :: AST -> AST+collapseNestedBlocks = everywhere collapse+ where+ collapse :: AST -> AST+ collapse (Block ss sts) = Block ss (concatMap go sts)+ collapse js = js+ go :: AST -> [AST]+ go (Block _ sts) = sts+ go s = [s]++collapseNestedIfs :: AST -> AST+collapseNestedIfs = everywhere collapse+ where+ collapse :: AST -> AST+ collapse (IfElse s1 cond1 (Block _ [IfElse s2 cond2 body Nothing]) Nothing) =+ IfElse s1 (Binary s2 And cond1 cond2) body Nothing+ collapse js = js
+ src/Language/PureScript/CoreImp/Optimizer/Common.hs view
@@ -0,0 +1,76 @@+-- | Common functions used by the various optimizer phases+module Language.PureScript.CoreImp.Optimizer.Common where++import Prelude.Compat++import Data.Text (Text)+import Data.List (foldl')+import Data.Maybe (fromMaybe)++import Language.PureScript.Crash+import Language.PureScript.CoreImp.AST+import Language.PureScript.PSString (PSString)++applyAll :: [a -> a] -> a -> a+applyAll = foldl' (.) id++replaceIdent :: Text -> AST -> AST -> AST+replaceIdent var1 js = everywhere replace+ where+ replace (Var _ var2) | var1 == var2 = js+ replace other = other++replaceIdents :: [(Text, AST)] -> AST -> AST+replaceIdents vars = everywhere replace+ where+ replace v@(Var _ var) = fromMaybe v $ lookup var vars+ replace other = other++isReassigned :: Text -> AST -> Bool+isReassigned var1 = everything (||) check+ where+ check :: AST -> Bool+ check (Function _ _ args _) | var1 `elem` args = True+ check (VariableIntroduction _ arg _) | var1 == arg = True+ check (Assignment _ (Var _ arg) _) | var1 == arg = True+ check (For _ arg _ _ _) | var1 == arg = True+ check (ForIn _ arg _ _) | var1 == arg = True+ check _ = False++isRebound :: AST -> AST -> Bool+isRebound js d = any (\v -> isReassigned v d || isUpdated v d) (everything (++) variablesOf js)+ where+ variablesOf (Var _ var) = [var]+ variablesOf _ = []++isUsed :: Text -> AST -> Bool+isUsed var1 = everything (||) check+ where+ check :: AST -> Bool+ check (Var _ var2) | var1 == var2 = True+ check (Assignment _ target _) | var1 == targetVariable target = True+ check _ = False++targetVariable :: AST -> Text+targetVariable (Var _ var) = var+targetVariable (Indexer _ _ tgt) = targetVariable tgt+targetVariable _ = internalError "Invalid argument to targetVariable"++isUpdated :: Text -> AST -> Bool+isUpdated var1 = everything (||) check+ where+ check :: AST -> Bool+ check (Assignment _ target _) | var1 == targetVariable target = True+ check _ = False++removeFromBlock :: ([AST] -> [AST]) -> AST -> AST+removeFromBlock go (Block ss sts) = Block ss (go sts)+removeFromBlock _ js = js++isDict :: (Text, PSString) -> AST -> Bool+isDict (moduleName, dictName) (Indexer _ (StringLiteral _ x) (Var _ y)) =+ x == dictName && y == moduleName+isDict _ _ = False++isDict' :: [(Text, PSString)] -> AST -> Bool+isDict' xs js = any (`isDict` js) xs
+ src/Language/PureScript/CoreImp/Optimizer/Inliner.hs view
@@ -0,0 +1,383 @@+-- | This module performs basic inlining of known functions+module Language.PureScript.CoreImp.Optimizer.Inliner+ ( inlineVariables+ , inlineCommonValues+ , inlineCommonOperators+ , inlineFnComposition+ , inlineUnsafePartial+ , etaConvert+ , unThunk+ , evaluateIifes+ ) where++import Prelude.Compat++import Control.Monad.Supply.Class (MonadSupply, freshName)++import Data.Maybe (fromMaybe)+import Data.Monoid ((<>))+import Data.String (IsString, fromString)+import Data.Text (Text)+import qualified Data.Text as T++import Language.PureScript.PSString (PSString)+import Language.PureScript.CoreImp.AST+import Language.PureScript.CoreImp.Optimizer.Common+import qualified Language.PureScript.Constants as C++-- TODO: Potential bug:+-- Shouldn't just inline this case: { var x = 0; x.toFixed(10); }+-- Needs to be: { 0..toFixed(10); }+-- Probably needs to be fixed in pretty-printer instead.+shouldInline :: AST -> Bool+shouldInline (Var _ _) = True+shouldInline (NumericLiteral _ _) = True+shouldInline (StringLiteral _ _) = True+shouldInline (BooleanLiteral _ _) = True+shouldInline (Indexer _ index val) = shouldInline index && shouldInline val+shouldInline _ = False++etaConvert :: AST -> AST+etaConvert = everywhere convert+ where+ convert :: AST -> AST+ convert (Block ss [Return _ (App _ (Function _ Nothing idents block@(Block _ body)) args)])+ | all shouldInline args &&+ not (any (`isRebound` block) (map (Var Nothing) idents)) &&+ not (any (`isRebound` block) args)+ = Block ss (map (replaceIdents (zip idents args)) body)+ convert (Function _ Nothing [] (Block _ [Return _ (App _ fn [])])) = fn+ convert js = js++unThunk :: AST -> AST+unThunk = everywhere convert+ where+ convert :: AST -> AST+ convert (Block ss []) = Block ss []+ convert (Block ss jss) =+ case last jss of+ Return _ (App _ (Function _ Nothing [] (Block _ body)) []) -> Block ss $ init jss ++ body+ _ -> Block ss jss+ convert js = js++evaluateIifes :: AST -> AST+evaluateIifes = everywhere convert+ where+ convert :: AST -> AST+ convert (App _ (Function _ Nothing [] (Block _ [Return _ ret])) []) = ret+ convert (App _ (Function _ Nothing idents (Block _ [Return ss ret])) [])+ | not (any (`isReassigned` ret) idents) = replaceIdents (map (, Var ss C.undefined) idents) ret+ convert js = js++inlineVariables :: AST -> AST+inlineVariables = everywhere $ removeFromBlock go+ where+ go :: [AST] -> [AST]+ go [] = []+ go (VariableIntroduction _ var (Just js) : sts)+ | shouldInline js && not (any (isReassigned var) sts) && not (any (isRebound js) sts) && not (any (isUpdated var) sts) =+ go (map (replaceIdent var js) sts)+ go (s:sts) = s : go sts++inlineCommonValues :: AST -> AST+inlineCommonValues = everywhere convert+ where+ convert :: AST -> AST+ convert (App ss fn [dict])+ | isDict' [semiringNumber, semiringInt] dict && isDict fnZero fn = NumericLiteral ss (Left 0)+ | isDict' [semiringNumber, semiringInt] dict && isDict fnOne fn = NumericLiteral ss (Left 1)+ | isDict boundedBoolean dict && isDict fnBottom fn = BooleanLiteral ss False+ | isDict boundedBoolean dict && isDict fnTop fn = BooleanLiteral ss True+ convert (App ss (App _ fn [dict]) [x])+ | isDict ringInt dict && isDict fnNegate fn = Binary ss BitwiseOr (Unary ss Negate x) (NumericLiteral ss (Left 0))+ convert (App ss (App _ (App _ fn [dict]) [x]) [y])+ | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add x y+ | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply x y+ | isDict euclideanRingInt dict && isDict fnDivide fn = intOp ss Divide x y+ | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract x y+ convert other = other+ fnZero = (C.dataSemiring, C.zero)+ fnOne = (C.dataSemiring, C.one)+ fnBottom = (C.dataBounded, C.bottom)+ fnTop = (C.dataBounded, C.top)+ fnAdd = (C.dataSemiring, C.add)+ fnDivide = (C.dataEuclideanRing, C.div)+ fnMultiply = (C.dataSemiring, C.mul)+ fnSubtract = (C.dataRing, C.sub)+ fnNegate = (C.dataRing, C.negate)+ intOp ss op x y = Binary ss BitwiseOr (Binary ss op x y) (NumericLiteral ss (Left 0))++inlineCommonOperators :: AST -> AST+inlineCommonOperators = everywhereTopDown $ applyAll $+ [ binary semiringNumber opAdd Add+ , binary semiringNumber opMul Multiply++ , binary ringNumber opSub Subtract+ , unary ringNumber opNegate Negate++ , binary euclideanRingNumber opDiv Divide+ , binary euclideanRingInt opMod Modulus++ , binary eqNumber opEq EqualTo+ , binary eqNumber opNotEq NotEqualTo+ , binary eqInt opEq EqualTo+ , binary eqInt opNotEq NotEqualTo+ , binary eqString opEq EqualTo+ , binary eqString opNotEq NotEqualTo+ , binary eqChar opEq EqualTo+ , binary eqChar opNotEq NotEqualTo+ , binary eqBoolean opEq EqualTo+ , binary eqBoolean opNotEq NotEqualTo++ , binary ordBoolean opLessThan LessThan+ , binary ordBoolean opLessThanOrEq LessThanOrEqualTo+ , binary ordBoolean opGreaterThan GreaterThan+ , binary ordBoolean opGreaterThanOrEq GreaterThanOrEqualTo+ , binary ordChar opLessThan LessThan+ , binary ordChar opLessThanOrEq LessThanOrEqualTo+ , binary ordChar opGreaterThan GreaterThan+ , binary ordChar opGreaterThanOrEq GreaterThanOrEqualTo+ , binary ordInt opLessThan LessThan+ , binary ordInt opLessThanOrEq LessThanOrEqualTo+ , binary ordInt opGreaterThan GreaterThan+ , binary ordInt opGreaterThanOrEq GreaterThanOrEqualTo+ , binary ordNumber opLessThan LessThan+ , binary ordNumber opLessThanOrEq LessThanOrEqualTo+ , binary ordNumber opGreaterThan GreaterThan+ , binary ordNumber opGreaterThanOrEq GreaterThanOrEqualTo+ , binary ordString opLessThan LessThan+ , binary ordString opLessThanOrEq LessThanOrEqualTo+ , binary ordString opGreaterThan GreaterThan+ , binary ordString opGreaterThanOrEq GreaterThanOrEqualTo++ , binary semigroupString opAppend Add++ , binary heytingAlgebraBoolean opConj And+ , binary heytingAlgebraBoolean opDisj Or+ , unary heytingAlgebraBoolean opNot Not++ , binary' C.dataIntBits C.or BitwiseOr+ , binary' C.dataIntBits C.and BitwiseAnd+ , binary' C.dataIntBits C.xor BitwiseXor+ , binary' C.dataIntBits C.shl ShiftLeft+ , binary' C.dataIntBits C.shr ShiftRight+ , binary' C.dataIntBits C.zshr ZeroFillShiftRight+ , unary' C.dataIntBits C.complement BitwiseNot++ , inlineNonClassFunction (isModFn (C.dataFunction, C.apply)) $ \f x -> App Nothing f [x]+ , inlineNonClassFunction (isModFn (C.dataFunction, C.applyFlipped)) $ \x f -> App Nothing f [x]+ , inlineNonClassFunction (isModFnWithDict (C.dataArray, C.unsafeIndex)) $ flip (Indexer Nothing)+ ] +++ [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]+ where+ binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> AST -> AST+ binary dict fns op = convert where+ convert :: AST -> AST+ convert (App ss (App _ (App _ fn [dict']) [x]) [y]) | isDict dict dict' && isDict fns fn = Binary ss op x y+ convert other = other+ binary' :: Text -> PSString -> BinaryOperator -> AST -> AST+ binary' moduleName opString op = convert where+ convert :: AST -> AST+ convert (App ss (App _ fn [x]) [y]) | isDict (moduleName, opString) fn = Binary ss op x y+ convert other = other+ unary :: (Text, PSString) -> (Text, PSString) -> UnaryOperator -> AST -> AST+ unary dicts fns op = convert where+ convert :: AST -> AST+ convert (App ss (App _ fn [dict']) [x]) | isDict dicts dict' && isDict fns fn = Unary ss op x+ convert other = other+ unary' :: Text -> PSString -> UnaryOperator -> AST -> AST+ unary' moduleName fnName op = convert where+ convert :: AST -> AST+ convert (App ss fn [x]) | isDict (moduleName, fnName) fn = Unary ss op x+ convert other = other+ mkFn :: Int -> AST -> AST+ mkFn 0 = convert where+ convert :: AST -> AST+ convert (App _ mkFnN [Function s1 Nothing [_] (Block s2 js)]) | isNFn C.mkFn 0 mkFnN =+ Function s1 Nothing [] (Block s2 js)+ convert other = other+ mkFn n = convert where+ convert :: AST -> AST+ convert orig@(App ss mkFnN [fn]) | isNFn C.mkFn n mkFnN =+ case collectArgs n [] fn of+ Just (args, js) -> Function ss Nothing args (Block ss js)+ Nothing -> orig+ convert other = other+ collectArgs :: Int -> [Text] -> AST -> Maybe ([Text], [AST])+ collectArgs 1 acc (Function _ Nothing [oneArg] (Block _ js)) | length acc == n - 1 = Just (reverse (oneArg : acc), js)+ collectArgs m acc (Function _ Nothing [oneArg] (Block _ [Return _ ret])) = collectArgs (m - 1) (oneArg : acc) ret+ collectArgs _ _ _ = Nothing++ isNFn :: Text -> Int -> AST -> Bool+ isNFn prefix n (Var _ name) = name == (prefix <> T.pack (show n))+ isNFn prefix n (Indexer _ (StringLiteral _ name) (Var _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried =+ name == fromString (T.unpack prefix <> show n)+ isNFn _ _ _ = False++ runFn :: Int -> AST -> AST+ runFn n = convert where+ convert :: AST -> AST+ convert js = fromMaybe js $ go n [] js++ go :: Int -> [AST] -> AST -> Maybe AST+ go 0 acc (App ss runFnN [fn]) | isNFn C.runFn n runFnN && length acc == n = Just (App ss fn acc)+ go m acc (App _ lhs [arg]) = go (m - 1) (arg : acc) lhs+ go _ _ _ = Nothing++ inlineNonClassFunction :: (AST -> Bool) -> (AST -> AST -> AST) -> AST -> AST+ inlineNonClassFunction p f = convert where+ convert :: AST -> AST+ convert (App _ (App _ op' [x]) [y]) | p op' = f x y+ convert other = other++ isModFn :: (Text, PSString) -> AST -> Bool+ isModFn (m, op) (Indexer _ (StringLiteral _ op') (Var _ m')) =+ m == m' && op == op'+ isModFn _ _ = False++ isModFnWithDict :: (Text, PSString) -> AST -> Bool+ isModFnWithDict (m, op) (App _ (Indexer _ (StringLiteral _ op') (Var _ m')) [Var _ _]) =+ m == m' && op == op'+ isModFnWithDict _ _ = False++-- (f <<< g $ x) = f (g x)+-- (f <<< g) = \x -> f (g x)+inlineFnComposition :: forall m. MonadSupply m => AST -> m AST+inlineFnComposition = everywhereTopDownM convert where+ convert :: AST -> m AST+ convert (App s1 (App s2 (App _ (App _ fn [dict']) [x]) [y]) [z])+ | isFnCompose dict' fn = return $ App s1 x [App s2 y [z]]+ | isFnComposeFlipped dict' fn = return $ App s2 y [App s1 x [z]]+ convert (App ss (App _ (App _ fn [dict']) [x]) [y])+ | isFnCompose dict' fn = do+ arg <- freshName+ return $ Function ss Nothing [arg] (Block ss [Return Nothing $ App Nothing x [App Nothing y [Var Nothing arg]]])+ | isFnComposeFlipped dict' fn = do+ arg <- freshName+ return $ Function ss Nothing [arg] (Block ss [Return Nothing $ App Nothing y [App Nothing x [Var Nothing arg]]])+ convert other = return other+ isFnCompose :: AST -> AST -> Bool+ isFnCompose dict' fn = isDict semigroupoidFn dict' && isDict fnCompose fn+ isFnComposeFlipped :: AST -> AST -> Bool+ isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isDict fnComposeFlipped fn+ fnCompose :: forall a b. (IsString a, IsString b) => (a, b)+ fnCompose = (C.controlSemigroupoid, C.compose)+ fnComposeFlipped :: forall a b. (IsString a, IsString b) => (a, b)+ fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)++inlineUnsafePartial :: AST -> AST+inlineUnsafePartial = everywhereTopDown convert where+ convert (App ss (Indexer _ (StringLiteral _ unsafePartial) (Var _ partialUnsafe)) [ comp ])+ | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe+ -- Apply to undefined here, the application should be optimized away+ -- if it is safe to do so+ = App ss comp [ Var ss C.undefined ]+ convert other = other++semiringNumber :: forall a b. (IsString a, IsString b) => (a, b)+semiringNumber = (C.dataSemiring, C.semiringNumber)++semiringInt :: forall a b. (IsString a, IsString b) => (a, b)+semiringInt = (C.dataSemiring, C.semiringInt)++ringNumber :: forall a b. (IsString a, IsString b) => (a, b)+ringNumber = (C.dataRing, C.ringNumber)++ringInt :: forall a b. (IsString a, IsString b) => (a, b)+ringInt = (C.dataRing, C.ringInt)++euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)+euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)++euclideanRingInt :: forall a b. (IsString a, IsString b) => (a, b)+euclideanRingInt = (C.dataEuclideanRing, C.euclideanRingInt)++eqNumber :: forall a b. (IsString a, IsString b) => (a, b)+eqNumber = (C.dataEq, C.eqNumber)++eqInt :: forall a b. (IsString a, IsString b) => (a, b)+eqInt = (C.dataEq, C.eqInt)++eqString :: forall a b. (IsString a, IsString b) => (a, b)+eqString = (C.dataEq, C.eqString)++eqChar :: forall a b. (IsString a, IsString b) => (a, b)+eqChar = (C.dataEq, C.eqChar)++eqBoolean :: forall a b. (IsString a, IsString b) => (a, b)+eqBoolean = (C.dataEq, C.eqBoolean)++ordBoolean :: forall a b. (IsString a, IsString b) => (a, b)+ordBoolean = (C.dataOrd, C.ordBoolean)++ordNumber :: forall a b. (IsString a, IsString b) => (a, b)+ordNumber = (C.dataOrd, C.ordNumber)++ordInt :: forall a b. (IsString a, IsString b) => (a, b)+ordInt = (C.dataOrd, C.ordInt)++ordString :: forall a b. (IsString a, IsString b) => (a, b)+ordString = (C.dataOrd, C.ordString)++ordChar :: forall a b. (IsString a, IsString b) => (a, b)+ordChar = (C.dataOrd, C.ordChar)++semigroupString :: forall a b. (IsString a, IsString b) => (a, b)+semigroupString = (C.dataSemigroup, C.semigroupString)++boundedBoolean :: forall a b. (IsString a, IsString b) => (a, b)+boundedBoolean = (C.dataBounded, C.boundedBoolean)++heytingAlgebraBoolean :: forall a b. (IsString a, IsString b) => (a, b)+heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)++semigroupoidFn :: forall a b. (IsString a, IsString b) => (a, b)+semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)++opAdd :: forall a b. (IsString a, IsString b) => (a, b)+opAdd = (C.dataSemiring, C.add)++opMul :: forall a b. (IsString a, IsString b) => (a, b)+opMul = (C.dataSemiring, C.mul)++opEq :: forall a b. (IsString a, IsString b) => (a, b)+opEq = (C.dataEq, C.eq)++opNotEq :: forall a b. (IsString a, IsString b) => (a, b)+opNotEq = (C.dataEq, C.notEq)++opLessThan :: forall a b. (IsString a, IsString b) => (a, b)+opLessThan = (C.dataOrd, C.lessThan)++opLessThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)+opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)++opGreaterThan :: forall a b. (IsString a, IsString b) => (a, b)+opGreaterThan = (C.dataOrd, C.greaterThan)++opGreaterThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)+opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)++opAppend :: forall a b. (IsString a, IsString b) => (a, b)+opAppend = (C.dataSemigroup, C.append)++opSub :: forall a b. (IsString a, IsString b) => (a, b)+opSub = (C.dataRing, C.sub)++opNegate :: forall a b. (IsString a, IsString b) => (a, b)+opNegate = (C.dataRing, C.negate)++opDiv :: forall a b. (IsString a, IsString b) => (a, b)+opDiv = (C.dataEuclideanRing, C.div)++opMod :: forall a b. (IsString a, IsString b) => (a, b)+opMod = (C.dataEuclideanRing, C.mod)++opConj :: forall a b. (IsString a, IsString b) => (a, b)+opConj = (C.dataHeytingAlgebra, C.conj)++opDisj :: forall a b. (IsString a, IsString b) => (a, b)+opDisj = (C.dataHeytingAlgebra, C.disj)++opNot :: forall a b. (IsString a, IsString b) => (a, b)+opNot = (C.dataHeytingAlgebra, C.not)
+ src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs view
@@ -0,0 +1,134 @@+-- | This module implements the "Magic Do" optimization, which inlines calls to return+-- and bind for the Eff monad, as well as some of its actions.+module Language.PureScript.CoreImp.Optimizer.MagicDo (magicDo) where++import Prelude.Compat+import Protolude (ordNub)++import Data.Maybe (fromJust, isJust)++import Language.PureScript.CoreImp.AST+import Language.PureScript.CoreImp.Optimizer.Common+import Language.PureScript.PSString (mkString)+import qualified Language.PureScript.Constants as C++-- | Inline type class dictionaries for >>= and return for the Eff monad+--+-- E.g.+--+-- Prelude[">>="](dict)(m1)(function(x) {+-- return ...;+-- })+--+-- becomes+--+-- function __do {+-- var x = m1();+-- ...+-- }+magicDo :: AST -> AST+magicDo = inlineST . everywhere undo . everywhereTopDown convert+ where+ -- The name of the function block which is added to denote a do block+ fnName = "__do"+ -- Desugar monomorphic calls to >>= and return for the Eff monad+ convert :: AST -> AST+ -- Desugar pure+ convert (App _ (App _ pure' [val]) []) | isPure pure' = val+ -- Desugar discard+ convert (App _ (App _ bind [m]) [Function s1 Nothing [] (Block s2 js)]) | isDiscard bind =+ Function s1 (Just fnName) [] $ Block s2 (App s2 m [] : map applyReturns js )+ -- Desugar bind+ convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 js)]) | isBind bind =+ Function s1 (Just fnName) [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns js)+ -- Desugar untilE+ convert (App s1 (App _ f [arg]) []) | isEffFunc C.untilE f =+ App s1 (Function s1 Nothing [] (Block s1 [ While s1 (Unary s1 Not (App s1 arg [])) (Block s1 []), Return s1 $ ObjectLiteral s1 []])) []+ -- Desugar whileE+ convert (App _ (App _ (App s1 f [arg1]) [arg2]) []) | isEffFunc C.whileE f =+ App s1 (Function s1 Nothing [] (Block s1 [ While s1 (App s1 arg1 []) (Block s1 [ App s1 arg2 [] ]), Return s1 $ ObjectLiteral s1 []])) []+ convert other = other+ -- Check if an expression represents a monomorphic call to >>= for the Eff monad+ isBind (App _ fn [dict]) | isDict (C.eff, C.bindEffDictionary) dict && isBindPoly fn = True+ isBind _ = False+ -- Check if an expression represents a call to @discard@+ isDiscard (App _ (App _ fn [dict1]) [dict2])+ | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&+ isDict (C.eff, C.bindEffDictionary) dict2 &&+ isDiscardPoly fn = True+ isDiscard _ = False+ -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative+ isPure (App _ fn [dict]) | isDict (C.eff, C.applicativeEffDictionary) dict && isPurePoly fn = True+ isPure _ = False+ -- Check if an expression represents the polymorphic >>= function+ isBindPoly = isDict (C.controlBind, C.bind)+ -- Check if an expression represents the polymorphic pure function+ isPurePoly = isDict (C.controlApplicative, C.pure')+ -- Check if an expression represents the polymorphic discard function+ isDiscardPoly = isDict (C.controlBind, C.discard)+ -- Check if an expression represents a function in the Eff module+ isEffFunc name (Indexer _ (StringLiteral _ name') (Var _ eff)) = eff == C.eff && name == name'+ isEffFunc _ _ = False++ -- Remove __do function applications which remain after desugaring+ undo :: AST -> AST+ undo (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body+ undo other = other++ applyReturns :: AST -> AST+ applyReturns (Return ss ret) = Return ss (App ss ret [])+ applyReturns (Block ss jss) = Block ss (map applyReturns jss)+ applyReturns (While ss cond js) = While ss cond (applyReturns js)+ applyReturns (For ss v lo hi js) = For ss v lo hi (applyReturns js)+ applyReturns (ForIn ss v xs js) = ForIn ss v xs (applyReturns js)+ applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)+ applyReturns other = other++-- | Inline functions in the ST module+inlineST :: AST -> AST+inlineST = everywhere convertBlock+ where+ -- Look for runST blocks and inline the STRefs there.+ -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then+ -- we can be more aggressive about inlining, and actually turn STRefs into local variables.+ convertBlock (App _ f [arg]) | isSTFunc C.runST f =+ let refs = ordNub . findSTRefsIn $ arg+ usages = findAllSTUsagesIn arg+ allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages+ localVarsDoNotEscape = all (\r -> length (r `appearingIn` arg) == length (filter (\u -> let v = toVar u in v == Just r) usages)) refs+ in everywhere (convert (allUsagesAreLocalVars && localVarsDoNotEscape)) arg+ convertBlock other = other+ -- Convert a block in a safe way, preserving object wrappers of references,+ -- or in a more aggressive way, turning wrappers into local variables depending on the+ -- agg(ressive) parameter.+ convert agg (App s1 f [arg]) | isSTFunc C.newSTRef f =+ Function s1 Nothing [] (Block s1 [Return s1 $ if agg then arg else ObjectLiteral s1 [(mkString C.stRefValue, arg)]])+ convert agg (App _ (App s1 f [ref]) []) | isSTFunc C.readSTRef f =+ if agg then ref else Indexer s1 (StringLiteral s1 C.stRefValue) ref+ convert agg (App _ (App _ (App s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =+ if agg then Assignment s1 ref arg else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) arg+ convert agg (App _ (App _ (App s1 f [ref]) [func]) []) | isSTFunc C.modifySTRef f =+ if agg then Assignment s1 ref (App s1 func [ref]) else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) (App s1 func [Indexer s1 (StringLiteral s1 C.stRefValue) ref])+ convert _ other = other+ -- Check if an expression represents a function in the ST module+ isSTFunc name (Indexer _ (StringLiteral _ name') (Var _ st)) = st == C.st && name == name'+ isSTFunc _ _ = False+ -- Find all ST Refs initialized in this block+ findSTRefsIn = everything (++) isSTRef+ where+ isSTRef (VariableIntroduction _ ident (Just (App _ (App _ f [_]) []))) | isSTFunc C.newSTRef f = [ident]+ isSTRef _ = []+ -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef+ findAllSTUsagesIn = everything (++) isSTUsage+ where+ isSTUsage (App _ (App _ f [ref]) []) | isSTFunc C.readSTRef f = [ref]+ isSTUsage (App _ (App _ (App _ f [ref]) [_]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]+ isSTUsage _ = []+ -- Find all uses of a variable+ appearingIn ref = everything (++) isVar+ where+ isVar e@(Var _ v) | v == ref = [e]+ isVar _ = []+ -- Convert a AST value to a String if it is a Var+ toVar (Var _ v) = Just v+ toVar _ = Nothing
+ src/Language/PureScript/CoreImp/Optimizer/TCO.hs view
@@ -0,0 +1,123 @@+-- | This module implements tail call elimination.+module Language.PureScript.CoreImp.Optimizer.TCO (tco) where++import Prelude.Compat++import Data.Text (Text)+import Data.Monoid ((<>))+import Language.PureScript.CoreImp.AST+import Language.PureScript.AST.SourcePos (SourceSpan)++-- | Eliminate tail calls+tco :: AST -> AST+tco = everywhere convert where+ tcoVar :: Text -> Text+ tcoVar arg = "__tco_" <> arg++ copyVar :: Text -> Text+ copyVar arg = "__copy_" <> arg++ tcoDone :: Text+ tcoDone = tcoVar "done"++ tcoLoop :: Text+ tcoLoop = tcoVar "loop"++ tcoResult :: Text+ tcoResult = tcoVar "result"++ convert :: AST -> AST+ convert (VariableIntroduction ss name (Just fn@Function {}))+ | isTailRecursive name body'+ = VariableIntroduction ss name (Just (replace (toLoop name allArgs body')))+ where+ (argss, body', replace) = collectAllFunctionArgs [] id fn+ allArgs = concat $ reverse argss+ convert js = js++ collectAllFunctionArgs :: [[Text]] -> (AST -> AST) -> AST -> ([[Text]], AST, AST -> AST)+ collectAllFunctionArgs allArgs f (Function s1 ident args (Block s2 (body@(Return _ _):_))) =+ collectAllFunctionArgs (args : allArgs) (\b -> f (Function s1 ident (map copyVar args) (Block s2 [b]))) body+ collectAllFunctionArgs allArgs f (Function ss ident args body@(Block _ _)) =+ (args : allArgs, body, f . Function ss ident (map copyVar args))+ collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args (Block s3 [body]))) =+ collectAllFunctionArgs (args : allArgs) (\b -> f (Return s1 (Function s2 ident (map copyVar args) (Block s3 [b])))) body+ collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args body@(Block _ _))) =+ (args : allArgs, body, f . Return s1 . Function s2 ident (map copyVar args))+ collectAllFunctionArgs allArgs f body = (allArgs, body, f)++ isTailRecursive :: Text -> AST -> Bool+ isTailRecursive ident js = countSelfReferences js > 0 && allInTailPosition js where+ countSelfReferences = everything (+) match where+ match :: AST -> Int+ match (Var _ ident') | ident == ident' = 1+ match _ = 0++ allInTailPosition (Return _ expr)+ | isSelfCall ident expr = countSelfReferences expr == 1+ | otherwise = countSelfReferences expr == 0+ allInTailPosition (While _ js1 body)+ = countSelfReferences js1 == 0 && allInTailPosition body+ allInTailPosition (For _ _ js1 js2 body)+ = countSelfReferences js1 == 0 && countSelfReferences js2 == 0 && allInTailPosition body+ allInTailPosition (ForIn _ _ js1 body)+ = countSelfReferences js1 == 0 && allInTailPosition body+ allInTailPosition (IfElse _ js1 body el)+ = countSelfReferences js1 == 0 && allInTailPosition body && all allInTailPosition el+ allInTailPosition (Block _ body)+ = all allInTailPosition body+ allInTailPosition (Throw _ js1)+ = countSelfReferences js1 == 0+ allInTailPosition _+ = False++ toLoop :: Text -> [Text] -> AST -> AST+ toLoop ident allArgs js =+ Block rootSS $+ map (\arg -> VariableIntroduction rootSS arg (Just (Var rootSS (copyVar arg)))) allArgs +++ [ VariableIntroduction rootSS tcoDone (Just (BooleanLiteral rootSS False))+ , VariableIntroduction rootSS tcoResult Nothing+ ] +++ map (\arg ->+ VariableIntroduction rootSS (tcoVar arg) Nothing) allArgs +++ [ Function rootSS (Just tcoLoop) allArgs (Block rootSS [loopify js])+ , While rootSS (Unary rootSS Not (Var rootSS tcoDone))+ (Block rootSS+ (Assignment rootSS (Var rootSS tcoResult) (App rootSS (Var rootSS tcoLoop) (map (Var rootSS) allArgs))+ : map (\arg ->+ Assignment rootSS (Var rootSS arg) (Var rootSS (tcoVar arg))) allArgs))+ , Return rootSS (Var rootSS tcoResult)+ ]+ where+ rootSS = Nothing++ loopify :: AST -> AST+ loopify (Return ss ret)+ | isSelfCall ident ret =+ let+ allArgumentValues = concat $ collectArgs [] ret+ in+ Block ss $+ zipWith (\val arg ->+ Assignment ss (Var ss (tcoVar arg)) val) allArgumentValues allArgs+ ++ [ ReturnNoResult ss ]+ | otherwise = Block ss [ markDone ss, Return ss ret ]+ loopify (ReturnNoResult ss) = Block ss [ markDone ss, ReturnNoResult ss ]+ loopify (While ss cond body) = While ss cond (loopify body)+ loopify (For ss i js1 js2 body) = For ss i js1 js2 (loopify body)+ loopify (ForIn ss i js1 body) = ForIn ss i js1 (loopify body)+ loopify (IfElse ss cond body el) = IfElse ss cond (loopify body) (fmap loopify el)+ loopify (Block ss body) = Block ss (map loopify body)+ loopify other = other++ markDone :: Maybe SourceSpan -> AST+ markDone ss = Assignment ss (Var ss tcoDone) (BooleanLiteral ss True)++ collectArgs :: [[AST]] -> AST -> [[AST]]+ collectArgs acc (App _ fn args') = collectArgs (args' : acc) fn+ collectArgs acc _ = acc++ isSelfCall :: Text -> AST -> Bool+ isSelfCall ident (App _ (Var _ ident') _) = ident == ident'+ isSelfCall ident (App _ fn _) = isSelfCall ident fn+ isSelfCall _ _ = False
+ src/Language/PureScript/CoreImp/Optimizer/Unused.hs view
@@ -0,0 +1,34 @@+-- | Removes unused variables+module Language.PureScript.CoreImp.Optimizer.Unused+ ( removeCodeAfterReturnStatements+ , removeUnusedArg+ , removeUndefinedApp+ ) where++import Prelude.Compat++import Language.PureScript.CoreImp.AST+import Language.PureScript.CoreImp.Optimizer.Common+import qualified Language.PureScript.Constants as C++removeCodeAfterReturnStatements :: AST -> AST+removeCodeAfterReturnStatements = everywhere (removeFromBlock go)+ where+ go :: [AST] -> [AST]+ go jss | not (any isReturn jss) = jss+ | otherwise = let (body, ret : _) = break isReturn jss in body ++ [ret]+ isReturn (Return _ _) = True+ isReturn (ReturnNoResult _) = True+ isReturn _ = False++removeUnusedArg :: AST -> AST+removeUnusedArg = everywhere convert+ where+ convert (Function ss name [arg] body) | arg == C.__unused = Function ss name [] body+ convert js = js++removeUndefinedApp :: AST -> AST+removeUndefinedApp = everywhere convert+ where+ convert (App ss fn [Var _ arg]) | arg == C.undefined = App ss fn []+ convert js = js
src/Language/PureScript/Docs/AsHtml.hs view
@@ -55,7 +55,7 @@ { currentModuleName :: P.ModuleName , buildDocLink :: Namespace -> Text -> ContainingModule -> Maybe DocLink , renderDocLink :: DocLink -> Text- , renderSourceLink :: P.SourceSpan -> Text+ , renderSourceLink :: P.SourceSpan -> Maybe Text } -- |@@ -65,7 +65,7 @@ { currentModuleName = mn , buildDocLink = const (const (const Nothing)) , renderDocLink = const ""- , renderSourceLink = const ""+ , renderSourceLink = const Nothing } packageAsHtml :: (P.ModuleName -> HtmlRenderContext) -> Package a -> HtmlOutput Html@@ -155,8 +155,11 @@ where linkToSource :: HtmlRenderContext -> P.SourceSpan -> Html linkToSource ctx srcspan =- H.span ! A.class_ "decl__source" $- a ! A.href (v (renderSourceLink ctx srcspan)) $ text "Source"+ maybe (return ()) go (renderSourceLink ctx srcspan)+ where+ go href =+ H.span ! A.class_ "decl__source" $+ a ! A.href (v href) $ text "Source" renderChildren :: HtmlRenderContext -> [ChildDeclaration] -> Html renderChildren _ [] = return ()
src/Language/PureScript/Docs/Convert/ReExports.hs view
@@ -455,7 +455,7 @@ ++ T.unpack cdeclTitle) addConstraint constraint =- P.quantify . P.moveQuantifiersToFront . P.ConstrainedType [constraint]+ P.quantify . P.moveQuantifiersToFront . P.ConstrainedType constraint splitMap :: Map k (v1, v2) -> (Map k v1, Map k v2) splitMap = fmap fst &&& fmap snd
src/Language/PureScript/Docs/Convert/Single.hs view
@@ -99,7 +99,7 @@ basicDeclaration title info = Just $ Right $ mkDeclaration title info convertDeclaration :: P.Declaration -> Text -> Maybe IntermediateDeclaration-convertDeclaration (P.ValueDeclaration _ _ _ (Right (P.TypedValue _ _ ty))) title =+convertDeclaration (P.ValueDeclaration _ _ _ [P.MkUnguarded (P.TypedValue _ _ ty)]) title = basicDeclaration title (ValueDeclaration ty) convertDeclaration P.ValueDeclaration{} title = -- If no explicit type declaration was provided, insert a wildcard, so that
src/Language/PureScript/Docs/Prim.hs view
@@ -25,10 +25,10 @@ , partial , fail , warn+ , union , typeConcat , typeString , kindType- , kindEffect , kindSymbol ] , modReExports = []@@ -95,11 +95,6 @@ , "For example the type `Boolean` has kind `Type`; denoted by `Boolean :: Type`." ] -kindEffect :: Declaration-kindEffect = primKind "Effect" $ T.unlines- [ "`Effect` (also known as `!`) is the kind of all effect types."- ]- kindSymbol :: Declaration kindSymbol = primKind "Symbol" $ T.unlines [ "`Symbol` is the kind of type-level strings."@@ -232,6 +227,14 @@ , "" , "For more information, see" , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."+ ]++union :: Declaration+union = primClass "Union" $ T.unlines+ [ "The Union type class is used to compute the union of two rows of types"+ , "(left-biased, including duplicates)."+ , ""+ , "The third type argument represents the union of the first two." ] typeConcat :: Declaration
src/Language/PureScript/Docs/RenderedCode/RenderType.hs view
@@ -62,17 +62,13 @@ let instApp = foldl TypeApp (TypeConstructor (fmap coerceProperName pn)) tys in renderType instApp -renderConstraints :: [Constraint] -> RenderedCode -> RenderedCode-renderConstraints deps ty =+renderConstraints :: Constraint -> RenderedCode -> RenderedCode+renderConstraints con ty = mintersperse sp- [ if length deps == 1- then constraints- else syntax "(" <> constraints <> syntax ")"+ [ renderConstraint con , syntax "=>" , ty ]- where- constraints = mintersperse (syntax "," <> sp) (map renderConstraint deps) -- | -- Render code representing a Row@@ -115,10 +111,10 @@ match (KindedType t k) = Just (k, t) match _ = Nothing -constrained :: Pattern () Type ([Constraint], Type)+constrained :: Pattern () Type (Constraint, Type) constrained = mkPattern match where- match (ConstrainedType deps ty) = Just (deps, ty)+ match (ConstrainedType con ty) = Just (con, ty) match _ = Nothing explicitParens :: Pattern () Type ((), Type)
src/Language/PureScript/Docs/Types.hs view
@@ -63,6 +63,8 @@ type UploadedPackage = Package NotYetKnown type VerifiedPackage = Package GithubUser +type ManifestError = BowerError+ verifyPackage :: GithubUser -> UploadedPackage -> VerifiedPackage verifyPackage verifiedUser Package{..} = Package pkgMeta@@ -327,7 +329,7 @@ = CompilerTooOld Version Version -- ^ Minimum allowable version for generating data with the current -- parser, and actual version used.- | ErrorInPackageMeta BowerError+ | ErrorInPackageMeta ManifestError | InvalidVersion | InvalidDeclarationType Text | InvalidChildDeclarationType Text@@ -564,7 +566,7 @@ pOr :: Parse e a -> Parse e a -> Parse e a p `pOr` q = catchError p (const q) -asInPackage :: Parse BowerError a -> Parse BowerError (InPackage a)+asInPackage :: Parse ManifestError a -> Parse ManifestError (InPackage a) asInPackage inner = build <$> key "package" (perhaps (withText parsePackageName)) <*> key "item" inner@@ -684,7 +686,7 @@ -- This is here to preserve backwards compatibility with compilers which used -- to generate a 'bookmarks' field in the JSON (i.e. up to 0.10.5). We should -- remove this after the next breaking change to the JSON.-bookmarksAsModuleMap :: Parse BowerError (Map P.ModuleName PackageName)+bookmarksAsModuleMap :: Parse ManifestError (Map P.ModuleName PackageName) bookmarksAsModuleMap = convert <$> eachInArray (asInPackage (nth 0 (P.moduleNameFromString <$> asText)))
src/Language/PureScript/Environment.hs view
@@ -1,26 +1,24 @@-{-# LANGUAGE TemplateHaskell #-}- module Language.PureScript.Environment where -import Prelude.Compat+import Prelude.Compat+import Protolude (ordNub) -import Data.Aeson.TH+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 Data.Maybe (fromMaybe, mapMaybe)+import Data.Text (Text) import qualified Data.Text as T-import Data.List (nub)-import Data.Tree (Tree, rootLabel)+import Data.Tree (Tree, rootLabel) import qualified Data.Graph as G-import Data.Foldable (toList)+import Data.Foldable (toList) -import Language.PureScript.Crash-import Language.PureScript.Kinds-import Language.PureScript.Names-import Language.PureScript.TypeClassDictionaries-import Language.PureScript.Types+import Language.PureScript.Crash+import Language.PureScript.Kinds+import Language.PureScript.Names+import Language.PureScript.TypeClassDictionaries+import Language.PureScript.Types import qualified Language.PureScript.Constants as C -- | The @Environment@ defines all values and types which are currently in scope:@@ -72,14 +70,23 @@ -- ^ the determined type arguments } deriving Show --- |--- The initial environment with no values and only the default javascript types defined---+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 primTypes M.empty M.empty M.empty primClasses primKinds --- |--- A constructor for TypeClassData that computes which type class arguments are fully determined+-- | 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@@ -119,7 +126,7 @@ (src, fdDetermined fd) : map (, []) (fdDetermined fd) -- build a graph of which arguments determine other arguments- (depGraph, fromVertex, fromKey) = G.graphFromEdges ((\(n, v) -> (n, n, nub v)) <$> M.toList contributingDeps)+ (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@@ -151,77 +158,69 @@ coveringSets = let funDepSets = sequence (mapMaybe sccNonDetermined (G.scc depGraph)) in S.fromList (S.fromList <$> funDepSets) --- |--- The visibility of a name in scope---+-- | The visibility of a name in scope data NameVisibility- -- |- -- The name is defined in the current binding group, but is not visible- -- = Undefined- -- |- -- The name is defined in the another binding group, or has been made visible by a function binder- --- | Defined deriving (Show, Eq)+ -- ^ 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) --- |--- A flag for whether a name is for an private or public value - only public values will be+-- | 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- -- |- -- A private value introduced as an artifact of code generation (class instances, class member- -- accessors, etc.)- -- = Private- -- |- -- A public value for a module member or foreing import declaration- --+ -- ^ A private value introduced as an artifact of code generation (class instances, class member+ -- accessors, etc.) | Public- -- |- -- A name for member introduced by foreign import- --+ -- ^ A public value for a module member or foreing import declaration | External+ -- ^ A name for member introduced by foreign import deriving (Show, Eq) --- |--- The kinds of a type---+-- | The kinds of a type data TypeKind- -- |- -- Data type- -- = DataType [(Text, Maybe Kind)] [(ProperName 'ConstructorName, [Type])]- -- |- -- Type synonym- --+ -- ^ Data type | TypeSynonym- -- |- -- Foreign data- --+ -- ^ Type synonym | ExternData- -- |- -- A local type variable- --+ -- ^ Foreign data | LocalTypeVariable- -- |- -- A scoped type variable- --+ -- ^ A local type variable | ScopedTypeVar+ -- ^ A scoped type variable deriving (Show, Eq) --- |--- The type ('data' or 'newtype') of a data type declaration---+instance A.ToJSON TypeKind where+ toJSON (DataType args ctors) =+ A.object [ T.pack "DataType" .= A.object ["args" .= args, "ctors" .= ctors] ]+ toJSON TypeSynonym = A.toJSON (T.pack "TypeSynonym")+ toJSON ExternData = A.toJSON (T.pack "ExternData")+ toJSON LocalTypeVariable = A.toJSON (T.pack "LocalTypeVariable")+ toJSON ScopedTypeVar = A.toJSON (T.pack "ScopedTypeVar")++instance A.FromJSON TypeKind where+ parseJSON (A.Object o) = do+ args <- o .: "DataType"+ A.withObject "args" (\o1 ->+ DataType <$> o1 .: "args"+ <*> o1 .: "ctors") args+ parseJSON (A.String s) =+ case s of+ "TypeSynonym" -> pure TypeSynonym+ "ExternData" -> pure ExternData+ "LocalTypeVariable" -> pure LocalTypeVariable+ "ScopedTypeVar" -> pure ScopedTypeVar+ _ -> fail "Unknown TypeKind"+ parseJSON _ = fail "Invalid TypeKind"++-- | The type ('data' or 'newtype') of a data type declaration data DataDeclType- -- |- -- A standard data constructor- -- = Data- -- |- -- A newtype constructor- --+ -- ^ A standard data constructor | Newtype+ -- ^ A newtype constructor deriving (Show, Eq, Ord) showDataDeclType :: DataDeclType -> Text@@ -238,90 +237,61 @@ "newtype" -> return Newtype other -> fail $ "invalid type: '" ++ T.unpack other ++ "'" --- |--- Construct a ProperName in the Prim module---+-- | Construct a ProperName in the Prim module primName :: Text -> Qualified (ProperName a) primName = Qualified (Just $ ModuleName [ProperName C.prim]) . ProperName primKind :: Text -> Kind primKind = NamedKind . primName --- |--- Kinds in prim---+-- | Kind of ground types kindType :: Kind kindType = primKind C.typ -kindEffect :: Kind-kindEffect = primKind C.effect- kindSymbol :: Kind kindSymbol = primKind C.symbol --- |--- Construct a type in the Prim module---+-- | Construct a type in the Prim module primTy :: Text -> Type primTy = TypeConstructor . primName --- |--- Type constructor for functions---+-- | Type constructor for functions tyFunction :: Type tyFunction = primTy "Function" --- |--- Type constructor for strings---+-- | Type constructor for strings tyString :: Type tyString = primTy "String" --- |--- Type constructor for strings---+-- | Type constructor for strings tyChar :: Type tyChar = primTy "Char" --- |--- Type constructor for numbers---+-- | Type constructor for numbers tyNumber :: Type tyNumber = primTy "Number" --- |--- Type constructor for integers---+-- | Type constructor for integers tyInt :: Type tyInt = primTy "Int" --- |--- Type constructor for booleans---+-- | Type constructor for booleans tyBoolean :: Type tyBoolean = primTy "Boolean" --- |--- Type constructor for arrays---+-- | Type constructor for arrays tyArray :: Type tyArray = primTy "Array" --- |--- Type constructor for records---+-- | Type constructor for records tyRecord :: Type tyRecord = primTy "Record" --- |--- Check whether a type is a record---+-- | Check whether a type is a record isObject :: Type -> Bool isObject = isTypeOrApplied tyRecord --- |--- Check whether a type is a function---+-- | Check whether a type is a function isFunction :: Type -> Bool isFunction = isTypeOrApplied tyFunction @@ -329,27 +299,21 @@ isTypeOrApplied t1 (TypeApp t2 _) = t1 == t2 isTypeOrApplied t1 t2 = t1 == t2 --- |--- Smart constructor for function types---+-- | Smart constructor for function types function :: Type -> Type -> Type function t1 = TypeApp (TypeApp tyFunction t1) --- |--- The primitive kinds+-- | The primitive kinds primKinds :: S.Set (Qualified (ProperName 'KindName)) primKinds = S.fromList [ primName C.typ- , primName C.effect , primName C.symbol ] --- |--- The primitive types in the external javascript environment with their+-- | The primitive types in the external javascript 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)) (Kind, TypeKind) primTypes = M.fromList@@ -362,46 +326,48 @@ , (primName "Int", (kindType, ExternData)) , (primName "Boolean", (kindType, ExternData)) , (primName "Partial", (kindType, ExternData))+ , (primName "Union", (FunKind (Row kindType) (FunKind (Row kindType) (FunKind (Row kindType) kindType)), ExternData)) , (primName "Fail", (FunKind kindSymbol kindType, ExternData)) , (primName "Warn", (FunKind kindSymbol kindType, ExternData)) , (primName "TypeString", (FunKind kindType kindSymbol, ExternData)) , (primName "TypeConcat", (FunKind kindSymbol (FunKind kindSymbol kindSymbol), ExternData)) ] --- |--- The primitive class map. This just contains the `Fail`, `Warn`, and `Partial`+-- | The primitive class map. This just contains the `Fail`, `Warn`, and `Partial` -- classes. `Partial` is used as a kind of magic constraint for partial -- functions. `Fail` is used for user-defined type errors. `Warn` for -- user-defined warnings.--- primClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData primClasses = M.fromList [ (primName "Partial", (makeTypeClassData [] [] [] []))+ -- class Fail (message :: Symbol) , (primName "Fail", (makeTypeClassData [("message", Just kindSymbol)] [] [] []))+ -- class Warn (message :: Symbol) , (primName "Warn", (makeTypeClassData [("message", Just kindSymbol)] [] [] []))+ -- class Union (l :: # Type) (r :: # Type) (u :: # Type) | l r -> u, r u -> l, u l -> r+ , (primName "Union", (makeTypeClassData+ [ ("l", Just (Row kindType))+ , ("r", Just (Row kindType))+ , ("u", Just (Row kindType))+ ] [] []+ [ FunctionalDependency [0, 1] [2]+ , FunctionalDependency [1, 2] [0]+ , FunctionalDependency [2, 0] [1]+ ])) ] --- |--- Finds information about data constructors from the current environment.---+-- | Finds information about data constructors from the current environment. lookupConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> (DataDeclType, ProperName 'TypeName, Type, [Ident]) lookupConstructor env ctor = fromMaybe (internalError "Data constructor not found") $ ctor `M.lookup` dataConstructors env --- |--- Checks whether a data constructor is for a newtype.---+-- | 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.---+-- | Finds information about values from the current environment. lookupValue :: Environment -> Qualified Ident -> Maybe (Type, NameKind, NameVisibility) lookupValue env ident = ident `M.lookup` names env--$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''TypeKind)-$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''FunctionalDependency)
src/Language/PureScript/Errors.hs view
@@ -7,6 +7,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Arrow ((&&&)) import Control.Monad@@ -14,10 +15,10 @@ import Control.Monad.Trans.State.Lazy import Control.Monad.Writer import Data.Char (isSpace)-import Data.Either (lefts, rights)+import Data.Either (partitionEithers) import Data.Foldable (fold) import Data.Functor.Identity (Identity(..))-import Data.List (transpose, nub, nubBy, sortBy, partition)+import Data.List (transpose, nubBy, sortBy, partition, dropWhileEnd) import Data.Maybe (maybeToList, fromMaybe, mapMaybe) import Data.Ord (comparing) import Data.String (fromString)@@ -122,6 +123,8 @@ PossiblyInfiniteInstance{} -> "PossiblyInfiniteInstance" CannotDerive{} -> "CannotDerive" InvalidNewtypeInstance{} -> "InvalidNewtypeInstance"+ InvalidDerivedInstance{} -> "InvalidDerivedInstance"+ ExpectedTypeConstructor{} -> "ExpectedTypeConstructor" CannotFindDerivingType{} -> "CannotFindDerivingType" DuplicateLabel{} -> "DuplicateLabel" DuplicateValueDeclaration{} -> "DuplicateValueDeclaration"@@ -171,6 +174,7 @@ CannotUseBindWithDo{} -> "CannotUseBindWithDo" ClassInstanceArityMismatch{} -> "ClassInstanceArityMismatch" UserDefinedWarning{} -> "UserDefinedWarning"+ UnusableDeclaration{} -> "UnusableDeclaration" -- | A stack trace for an error newtype MultipleErrors = MultipleErrors@@ -260,10 +264,12 @@ gSimple (PossiblyInfiniteInstance cl ts) = PossiblyInfiniteInstance cl <$> traverse f ts gSimple (CannotDerive cl ts) = CannotDerive cl <$> traverse f ts gSimple (InvalidNewtypeInstance cl ts) = InvalidNewtypeInstance cl <$> traverse f ts+ gSimple (InvalidDerivedInstance cl ts n) = InvalidDerivedInstance cl <$> traverse f ts <*> pure n+ gSimple (ExpectedTypeConstructor cl ts ty) = ExpectedTypeConstructor cl <$> traverse f ts <*> f ty gSimple (ExpectedType ty k) = ExpectedType <$> f ty <*> pure k gSimple (OrphanInstance nm cl ts) = OrphanInstance nm cl <$> traverse f ts gSimple (WildcardInferredType ty ctx) = WildcardInferredType <$> f ty <*> traverse (sndM f) ctx- gSimple (HoleInferredType name ty ctx env) = HoleInferredType name <$> f ty <*> traverse (sndM f) ctx <*> gTypeSearch env+ gSimple (HoleInferredType name ty ctx env) = HoleInferredType name <$> f ty <*> traverse (sndM f) ctx <*> onTypeSearchTypesM f env gSimple (MissingTypeDeclaration nm ty) = MissingTypeDeclaration nm <$> f ty gSimple (CannotGeneralizeRecursiveFunction nm ty) = CannotGeneralizeRecursiveFunction nm <$> f ty gSimple other = pure other@@ -277,9 +283,6 @@ gHint (ErrorSolvingConstraint con) = ErrorSolvingConstraint <$> overConstraintArgs (traverse f) con gHint other = pure other - gTypeSearch (TSBefore env) = pure (TSBefore env)- gTypeSearch (TSAfter result) = TSAfter <$> traverse (traverse f) result- errorDocUri :: ErrorMessage -> Text errorDocUri e = "https://github.com/purescript/documentation/blob/master/errors/" <> errorCode e <> ".md" @@ -490,8 +493,8 @@ line $ "The type declaration for " <> markCode (showIdent nm) <> " should be followed by its definition." renderSimpleErrorMessage (RedefinedIdent name) = line $ "The value " <> markCode (showIdent name) <> " has been defined multiple times"- renderSimpleErrorMessage (UnknownName name@(Qualified Nothing (IdentName (Ident "bind")))) =- line $ "Unknown " <> printName name <> ". You're probably using do-notation, which the compiler replaces with calls to the " <> markCode "bind" <> " function. Please import " <> markCode "bind" <> " from module " <> markCode "Prelude"+ renderSimpleErrorMessage (UnknownName name@(Qualified Nothing (IdentName (Ident i)))) | i `elem` [ C.bind, C.discard ] =+ line $ "Unknown " <> printName name <> ". You're probably using do-notation, which the compiler replaces with calls to the " <> markCode i <> " function. Please import " <> markCode i <> " from module " <> markCode "Prelude" renderSimpleErrorMessage (UnknownName name) = line $ "Unknown " <> printName name renderSimpleErrorMessage (UnknownImport mn name) =@@ -544,11 +547,16 @@ paras [ line $ "Type synonym " <> markCode (showQualified runProperName name) <> " is partially applied." , line "Type synonyms must be applied to all of their type arguments." ]- renderSimpleErrorMessage (EscapedSkolem binding) =- paras $ [ line "A type variable has escaped its scope." ]- <> foldMap (\expr -> [ line "Relevant expression: "- , markCodeBox $ indent $ prettyPrintValue valueDepth expr- ]) binding+ renderSimpleErrorMessage (EscapedSkolem name Nothing ty) =+ paras [ line $ "The type variable " <> markCode name <> " has escaped its scope, appearing in the type"+ , markCodeBox $ indent $ typeAsBox ty+ ]+ renderSimpleErrorMessage (EscapedSkolem name (Just srcSpan) ty) =+ paras [ line $ "The type variable " <> markCode name <> ", bound at"+ , indent $ line $ displaySourceSpan srcSpan+ , line "has escaped its scope, appearing in the type"+ , markCodeBox $ indent $ typeAsBox ty+ ] renderSimpleErrorMessage (TypesDoNotUnify u1 u2) = let (sorted1, sorted2) = sortRows u1 u2 @@ -611,13 +619,19 @@ _ (Just (PartialConstraintData bs b)))) = paras [ line "A case expression could not be determined to cover all inputs."- , line "The following additional cases are required to cover all inputs:\n"+ , line "The following additional cases are required to cover all inputs:" , indent $ paras $ Box.hsep 1 Box.left (map (paras . map (line . markCode)) (transpose bs)) : [line "..." | not b] , line "Alternatively, add a Partial constraint to the type of the enclosing value." ]+ renderSimpleErrorMessage (NoInstanceFound (Constraint C.Discard [ty] _)) =+ paras [ line "A result of type"+ , markCodeBox $ indent $ typeAsBox ty+ , line "was implicitly discarded in a do notation block."+ , line ("You can use " <> markCode "_ <- ..." <> " to explicitly discard the result.")+ ] renderSimpleErrorMessage (NoInstanceFound (Constraint nm ts _)) = paras [ line "No type class instance was found for" , markCodeBox $ indent $ Box.hsep 1 Box.left@@ -653,6 +667,7 @@ [ line (showQualified runProperName nm) , Box.vcat Box.left (map typeAtomAsBox ts) ]+ , line "since instances of this type class are not derivable." ] renderSimpleErrorMessage (InvalidNewtypeInstance nm ts) = paras [ line "Cannot derive newtype instance for"@@ -662,6 +677,32 @@ ] , line "Make sure this is a newtype." ]+ renderSimpleErrorMessage (InvalidDerivedInstance nm ts argCount) =+ paras [ line "Cannot derive the type class instance"+ , markCodeBox $ indent $ Box.hsep 1 Box.left+ [ line (showQualified runProperName nm)+ , Box.vcat Box.left (map typeAtomAsBox ts)+ ]+ , line $ fold $+ [ "because the "+ , markCode (showQualified runProperName nm)+ , " type class has "+ , T.pack (show argCount)+ , " type "+ , if argCount == 1 then "argument" else "arguments"+ , ", but the declaration specifies " <> T.pack (show (length ts)) <> "."+ ]+ ]+ renderSimpleErrorMessage (ExpectedTypeConstructor nm ts ty) =+ paras [ line "Cannot derive the type class instance"+ , markCodeBox $ indent $ Box.hsep 1 Box.left+ [ line (showQualified runProperName nm)+ , Box.vcat Box.left (map typeAtomAsBox ts)+ ]+ , "because the type"+ , markCodeBox $ indent $ typeAsBox ty+ , line "is not of the required form T a_1 ... a_n, where T is a type constructor defined in the same module."+ ] renderSimpleErrorMessage (CannotFindDerivingType nm) = line $ "Cannot derive a type class instance, because the type declaration for " <> markCode (runProperName nm) <> " could not be found." renderSimpleErrorMessage (DuplicateLabel l expr) =@@ -735,7 +776,7 @@ renderSimpleErrorMessage (ShadowedTypeVar tv) = line $ "Type variable " <> markCode tv <> " was shadowed." renderSimpleErrorMessage (UnusedTypeVar tv) =- line $ "Type variable " <> markCode tv <> " was declared but not used."+ line $ "Type variable " <> markCode tv <> " is ambiguous, since it is unused in the polymorphic type which introduces it." renderSimpleErrorMessage (MisleadingEmptyTypeImport mn name) = line $ "Importing type " <> markCode (runProperName name <> "(..)") <> " from " <> markCode (runModuleName mn) <> " is misleading as it has no exported data constructors." renderSimpleErrorMessage (ImportHidingModule name) =@@ -750,11 +791,11 @@ let maxTSResults = 15 tsResult = case ts of- (TSAfter idents) | not (null idents) ->+ (TSAfter{tsAfterIdentifiers=idents}) | not (null idents) -> let formatTS (names, types) = let- idBoxes = Box.text . T.unpack . showQualified runIdent <$> names+ idBoxes = Box.text . T.unpack . showQualified id <$> names tyBoxes = (\t -> BoxHelpers.indented (Box.text ":: " Box.<> typeAsBox t)) <$> types longestId = maximum (map Box.cols idBoxes)@@ -869,16 +910,18 @@ paras [ line $ "Expected a type wildcard (_) when deriving an instance for " <> markCode (runProperName tyName) <> "." ] - renderSimpleErrorMessage CannotUseBindWithDo =- paras [ line $ "The name " <> markCode "bind" <> " cannot be brought into scope in a do notation block, since do notation uses the same name."+ renderSimpleErrorMessage (CannotUseBindWithDo name) =+ paras [ line $ "The name " <> markCode (showIdent name) <> " cannot be brought into scope in a do notation block, since do notation uses the same name." ] renderSimpleErrorMessage (ClassInstanceArityMismatch dictName className expected actual) = paras [ line $ "The type class " <> markCode (showQualified runProperName className) <>- " expects " <> T.pack (show expected) <> " argument(s)."- , line $ "But the instance " <> markCode (showIdent dictName) <> " only provided " <>- T.pack (show actual) <> "."+ " expects " <> T.pack (show expected) <> " " <> argsMsg <> "."+ , line $ "But the instance " <> markCode (showIdent dictName) <> mismatchMsg <> T.pack (show actual) <> "." ]+ where+ mismatchMsg = if actual > expected then " provided " else " only provided "+ argsMsg = if expected > 1 then "arguments" else "argument" renderSimpleErrorMessage (UserDefinedWarning msgTy) = let msg = fromMaybe (typeAsBox msgTy) (toTypelevelString msgTy) in@@ -886,6 +929,11 @@ , indent msg ] + renderSimpleErrorMessage (UnusableDeclaration ident) =+ paras [ line $ "The declaration " <> markCode (showIdent ident) <> " is unusable."+ , line $ "This happens when a constraint couldn't possibly have enough information to work out which instance is required."+ ]+ renderHint :: ErrorMessageHint -> Box.Box -> Box.Box renderHint (ErrorUnifyingTypes t1 t2) detail = paras [ detail@@ -1242,7 +1290,7 @@ separate _ [m] = m separate sep (m:ms) = m ++ sep ++ separate sep ms - clean = nub . filter (not . null)+ clean = ordNub . filter (not . null) -- | Indent to the right, and pad on top and bottom. indent :: Box.Box -> Box.Box@@ -1262,7 +1310,6 @@ . lines . Box.render where- dropWhileEnd p = reverse . dropWhile p . reverse whiteSpace = all isSpace toTypelevelString :: Type -> Maybe Box.Box@@ -1278,7 +1325,7 @@ -- | Rethrow an error with a more detailed error message in the case of failure rethrow :: (MonadError e m) => (e -> e) -> m a -> m a-rethrow f = flip catchError $ \e -> throwError (f e)+rethrow f = flip catchError (throwError . f) reifyErrors :: (MonadError e m) => m a -> m (Either e a) reifyErrors ma = catchError (fmap Right ma) (return . Left)@@ -1330,6 +1377,6 @@ withError u = catchError (Right <$> u) (return . Left) collectErrors :: [Either MultipleErrors b] -> m [b]- collectErrors es = case lefts es of- [] -> return $ rights es- errs -> throwError $ fold errs+ collectErrors es = case partitionEithers es of+ ([], rs) -> return rs+ (errs, _) -> throwError $ fold errs
src/Language/PureScript/Externs.hs view
@@ -38,21 +38,22 @@ -- | The data which will be serialized to an externs file data ExternsFile = ExternsFile- {- -- | The externs version- efVersion :: Text- -- | Module name+ { efVersion :: Text+ -- ^ The externs version , efModuleName :: ModuleName- -- | List of module exports+ -- ^ Module name , efExports :: [DeclarationRef]- -- | List of module imports+ -- ^ List of module exports , efImports :: [ExternsImport]- -- | List of operators and their fixities+ -- ^ List of module imports , efFixities :: [ExternsFixity]- -- | List of type operators and their fixities+ -- ^ List of operators and their fixities , efTypeFixities :: [ExternsTypeFixity]- -- | List of type and value declaration+ -- ^ List of type operators and their fixities , efDeclarations :: [ExternsDeclaration]+ -- ^ List of type and value declaration+ , efSourceSpan :: SourceSpan+ -- ^ Source span for error reporting } deriving (Show) -- | A module import in an externs file@@ -165,7 +166,7 @@ -- | Generate an externs file for all declarations in a module moduleToExternsFile :: Module -> Environment -> ExternsFile moduleToExternsFile (Module _ _ _ _ Nothing) _ = internalError "moduleToExternsFile: module exports were not elaborated"-moduleToExternsFile (Module _ _ mn ds (Just exps)) env = ExternsFile{..}+moduleToExternsFile (Module ss _ mn ds (Just exps)) env = ExternsFile{..} where efVersion = T.pack (showVersion Paths.version) efModuleName = mn@@ -174,6 +175,7 @@ efFixities = mapMaybe fixityDecl ds efTypeFixities = mapMaybe typeFixityDecl ds efDeclarations = concatMap toExternsDeclaration efExports+ efSourceSpan = ss fixityDecl :: Declaration -> Maybe ExternsFixity fixityDecl (ValueFixityDeclaration (Fixity assoc prec) name op) =
src/Language/PureScript/Ide.hs view
@@ -67,7 +67,7 @@ List AvailableModules -> listAvailableModules List (Imports fp) ->- ImportList <$> getImportsForFile fp+ ImportList <$> parseImportsFromFile fp CaseSplit l b e wca t -> caseSplit l b e wca t AddClause l wca ->
src/Language/PureScript/Ide/Error.hs view
@@ -14,33 +14,62 @@ module Language.PureScript.Ide.Error ( IdeError(..)+ , prettyPrintTypeSingleLine ) where import Data.Aeson+import qualified Data.Aeson.Types as Aeson+import qualified Data.HashMap.Lazy as HM+import qualified Data.Text as T+import qualified Language.PureScript as P import Language.PureScript.Errors.JSON-import Language.PureScript.Ide.Types (ModuleIdent)+import Language.PureScript.Ide.Types (ModuleIdent, Completion(..)) import Protolude-import qualified Text.Parsec.Error as P+import qualified Text.Parsec.Error as Parsec data IdeError = GeneralError Text | NotFound Text | ModuleNotFound ModuleIdent | ModuleFileNotFound ModuleIdent- | ParseError P.ParseError Text- | RebuildError [JSONError]- deriving (Show, Eq)+ | ParseError Parsec.ParseError Text+ | RebuildError P.MultipleErrors+ deriving (Show) instance ToJSON IdeError where toJSON (RebuildError errs) = object [ "resultType" .= ("error" :: Text)- , "result" .= errs+ , "result" .= encodeRebuildErrors errs ] toJSON err = object [ "resultType" .= ("error" :: Text) , "result" .= textError err ] +encodeRebuildErrors :: P.MultipleErrors -> Value+encodeRebuildErrors = toJSON . map encodeRebuildError . P.runMultipleErrors+ where+ encodeRebuildError err = case err of+ (P.ErrorMessage _+ ((P.HoleInferredType name _ _+ (P.TSAfter{tsAfterIdentifiers=idents, tsAfterRecordFields=fields})))) ->+ insertTSCompletions name idents (fromMaybe [] fields) (toJSON (toJSONError False P.Error err))+ _ ->+ (toJSON . toJSONError False P.Error) err++ insertTSCompletions name idents fields (Aeson.Object value) =+ Aeson.Object+ (HM.insert "pursIde"+ (object [ "name" .= name+ , "completions" .= (ordNub (map identCompletion idents ++ map fieldCompletion fields))+ ]) value)+ insertTSCompletions _ _ _ v = v++ identCompletion (P.Qualified mn i, ty) =+ Completion (maybe "" P.runModuleName mn) i (prettyPrintTypeSingleLine ty) (prettyPrintTypeSingleLine ty) Nothing Nothing+ fieldCompletion (label, ty) =+ Completion "" ("_." <> P.prettyPrintLabel label) (prettyPrintTypeSingleLine ty) (prettyPrintTypeSingleLine ty) Nothing Nothing+ textError :: IdeError -> Text textError (GeneralError msg) = msg textError (NotFound ident) = "Symbol '" <> ident <> "' not found."@@ -52,3 +81,6 @@ -- over the socket as a single line in msg <> ": " <> escape parseError textError (RebuildError err) = show err++prettyPrintTypeSingleLine :: P.Type -> Text+prettyPrintTypeSingleLine = T.unwords . map T.strip . T.lines . T.pack . P.prettyPrintTypeWithUnicode
src/Language/PureScript/Ide/Externs.hs view
@@ -144,9 +144,9 @@ IdeDeclKind i -> annotateKind (i ^. properNameT) (IdeDeclKind i) where- annotateFunction x = IdeDeclarationAnn (ann { annLocation = Map.lookup (IdeNSValue (P.runIdent x)) defs- , annTypeAnnotation = Map.lookup x types+ annotateFunction x = IdeDeclarationAnn (ann { _annLocation = Map.lookup (IdeNSValue (P.runIdent x)) defs+ , _annTypeAnnotation = Map.lookup x types })- annotateValue x = IdeDeclarationAnn (ann {annLocation = Map.lookup (IdeNSValue x) defs})- annotateType x = IdeDeclarationAnn (ann {annLocation = Map.lookup (IdeNSType x) defs})- annotateKind x = IdeDeclarationAnn (ann {annLocation = Map.lookup (IdeNSKind x) defs})+ annotateValue x = IdeDeclarationAnn (ann {_annLocation = Map.lookup (IdeNSValue x) defs})+ annotateType x = IdeDeclarationAnn (ann {_annLocation = Map.lookup (IdeNSType x) defs})+ annotateKind x = IdeDeclarationAnn (ann {_annLocation = Map.lookup (IdeNSKind x) defs})
src/Language/PureScript/Ide/Imports.hs view
@@ -16,6 +16,7 @@ ( addImplicitImport , addImportForIdentifier , answerRequest+ , parseImportsFromFile -- for tests , parseImport , prettyPrintImportSection@@ -29,7 +30,7 @@ import Protolude -import Control.Lens ((^.))+import Control.Lens ((^.), (%~), ix) import Data.List (findIndex, nubBy) import qualified Data.Text as T import qualified Language.PureScript as P@@ -40,8 +41,9 @@ import Language.PureScript.Ide.Types import Language.PureScript.Ide.Util import System.IO.UTF8 (writeUTF8FileT)+import qualified Text.Parsec as Parsec -data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName)+data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName) deriving (Eq, Show) instance Ord Import where@@ -65,86 +67,80 @@ | not (P.isExplicit i) && isNothing q' = GT | otherwise = compare n n' +-- | Reads a file and returns the parsed modulename as well as the parsed+-- imports, while ignoring eventual parse errors that aren't relevant to the+-- import section+parseImportsFromFile+ :: (MonadIO m, MonadError IdeError m)+ => FilePath+ -> m (P.ModuleName, [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)])+parseImportsFromFile file = do+ (mn, _, imports, _) <- parseImportsFromFile' file+ pure (mn, unwrapImport <$> imports)+ where+ unwrapImport (Import a b c) = (a, b, c)+ -- | Reads a file and returns the (lines before the imports, the imports, the -- lines after the imports)-parseImportsFromFile :: (MonadIO m, MonadError IdeError m) =>+parseImportsFromFile' :: (MonadIO m, MonadError IdeError m) => FilePath -> m (P.ModuleName, [Text], [Import], [Text])-parseImportsFromFile fp = do+parseImportsFromFile' fp = do file <- ideReadFile fp case sliceImportSection (T.lines file) of Right res -> pure res Left err -> throwError (GeneralError err) -parseImportsWithModuleName :: [Text] -> Either Text (P.ModuleName, [Import])-parseImportsWithModuleName ls = do- (P.Module _ _ mn decls _) <- moduleParse ls- pure (mn, concatMap mkImport (unwrapPositioned <$> decls))+-- | @ImportParse@ holds the data we extract out of a partial parse of the+-- sourcefile+data ImportParse = ImportParse+ { ipModuleName :: P.ModuleName+ -- ^ the module name we parse+ , ipStart :: P.SourcePos+ -- ^ the beginning of the import section. If `import Prelude` was the first+ -- import, this would point at `i`+ , ipEnd :: P.SourcePos+ -- ^ the end of the import section+ , ipImports :: [Import]+ -- ^ the extracted import declarations+ }++parseModuleHeader :: P.TokenParser ImportParse+parseModuleHeader = do+ _ <- P.readComments+ (mn, _) <- P.parseModuleDeclaration+ (ipStart, ipEnd, decls) <- P.withSourceSpan (\(P.SourceSpan _ start end) _ -> (start, end,))+ (P.mark (Parsec.many (P.same *> P.parseImportDeclaration')))+ pure (ImportParse mn ipStart ipEnd (map mkImport decls)) where- mkImport (P.ImportDeclaration mn (P.Explicit refs) qual) =- [Import mn (P.Explicit (unwrapPositionedRef <$> refs)) qual]- mkImport (P.ImportDeclaration mn it qual) = [Import mn it qual]- mkImport _ = []+ mkImport (mn, (P.Explicit refs), qual) = Import mn (P.Explicit (unwrapPositionedRef <$> refs)) qual+ mkImport (mn, it, qual) = Import mn it qual sliceImportSection :: [Text] -> Either Text (P.ModuleName, [Text], [Import], [Text])-sliceImportSection ts =- case foldl step (ModuleHeader 0) (zip [0..] ts) of- Res start end ->- let- (moduleHeader, (importSection, remainingFile)) =- splitAt (succ (end - start)) `second` splitAt start ts- in- (\(mn, is) -> (mn, moduleHeader, is, remainingFile)) <$>- parseImportsWithModuleName (moduleHeader <> importSection)-- -- If we don't find any imports, we insert a newline after the module- -- declaration and begin a new importsection- ModuleHeader ix ->- let (moduleHeader, remainingFile) = splitAt (succ ix) ts- in- (\(mn, is) -> (mn, moduleHeader ++ [""], is, remainingFile)) <$>- parseImportsWithModuleName moduleHeader- _ -> Left "Failed to detect the import section"--data ImportStateMachine = ModuleHeader Int | ImportSection Int Int | Res Int Int---- | We start in the------ * ModuleHeader state.------ We skip every line we encounter, that doesn't start with "import". If we find--- a line that starts with module we store that linenumber. Once we find a line--- with "import" we store its linenumber as the start of the import section and--- change into the------ * ImportSection state------ For any line that starts with import or whitespace(is thus indented) we--- expand the end of the import section to that line and continue. If we--- encounter a commented or empty line, we continue moving forward in the--- ImportSection state but don't expand the import section end yet. This allows--- us to exclude newlines or comments that directly follow the import section.--- Once we encounter a line that is not a comment, newline, indentation or--- import we switch into the------ * Res state------ , which just shortcuts to the end of the file and carries the detected import--- section boundaries-step :: ImportStateMachine -> (Int, Text) -> ImportStateMachine-step (ModuleHeader mi) (ix, l)- | T.isPrefixOf "module " l = ModuleHeader ix- | T.isPrefixOf "import " l = ImportSection ix ix- | otherwise = ModuleHeader mi-step (ImportSection start lastImportLine) (ix, l)- | any (`T.isPrefixOf` l) ["import", " "] = ImportSection start ix- | T.isPrefixOf "--" l || l == "" = ImportSection start lastImportLine- | otherwise = Res start lastImportLine-step (Res start end) _ = Res start end--moduleParse :: [Text] -> Either Text P.Module-moduleParse t = first show $ do- tokens <- P.lex "" (T.unlines t)- P.runTokenParser "<psc-ide>" P.parseModule tokens+sliceImportSection fileLines = first show $ do+ tokens <- P.lexLenient "<psc-ide>" file+ ImportParse{..} <- P.runTokenParser "<psc-ide>" parseModuleHeader tokens+ pure ( ipModuleName+ , sliceFile (P.SourcePos 1 1) (prevPos ipStart)+ , ipImports+ -- Not sure why I need to drop 1 here, but it makes the tests pass+ , drop 1 (sliceFile (nextPos ipEnd) (P.SourcePos (length fileLines) (lineLength (length fileLines))))+ )+ where+ prevPos (P.SourcePos l c)+ | l == 1 && c == 1 = P.SourcePos l c+ | c == 1 = P.SourcePos (l - 1) (lineLength (l - 1))+ | otherwise = P.SourcePos l (c - 1)+ nextPos (P.SourcePos l c)+ | c == lineLength l = P.SourcePos (l + 1) 1+ | otherwise = P.SourcePos l (c + 1)+ file = T.unlines fileLines+ lineLength l = T.length (fileLines ^. ix (l - 1))+ sliceFile (P.SourcePos l1 c1) (P.SourcePos l2 c2) =+ fileLines+ & drop (l1 - 1)+ & take (l2 - l1 + 1)+ & ix 0 %~ T.drop (c1 - 1)+ & ix (l2 - l1) %~ T.take c2 -- | Adds an implicit import like @import Prelude@ to a Sourcefile. addImplicitImport :: (MonadIO m, MonadError IdeError m)@@ -152,9 +148,9 @@ -> P.ModuleName -- ^ The module to import -> m [Text] addImplicitImport fp mn = do- (_, pre, imports, post) <- parseImportsFromFile fp+ (_, pre, imports, post) <- parseImportsFromFile' fp let newImportSection = addImplicitImport' imports mn- pure $ pre ++ newImportSection ++ post+ pure (pre ++ newImportSection ++ post) addImplicitImport' :: [Import] -> P.ModuleName -> [Text] addImplicitImport' imports mn =@@ -173,7 +169,7 @@ addExplicitImport :: (MonadIO m, MonadError IdeError m) => FilePath -> IdeDeclaration -> P.ModuleName -> m [Text] addExplicitImport fp decl moduleName = do- (mn, pre, imports, post) <- parseImportsFromFile fp+ (mn, pre, imports, post) <- parseImportsFromFile' fp let newImportSection = -- TODO: Open an issue when this PR is merged, we should optimise this -- so that this case does not write to disc@@ -237,8 +233,8 @@ updateAtFirstOrPrepend p t d l = case findIndex p l of Nothing -> d : l- Just ix ->- let (x, a : y) = splitAt ix l+ Just i ->+ let (x, a : y) = splitAt i l in x ++ [t a] ++ y -- | Looks up the given identifier in the currently loaded modules.@@ -300,9 +296,6 @@ decideRedundantCase _ _ = Nothing prettyPrintImport' :: Import -> Text--- TODO: remove this clause once P.prettyPrintImport can properly handle PositionedRefs-prettyPrintImport' (Import mn (P.Explicit refs) qual) =- "import " <> P.prettyPrintImport mn (P.Explicit (unwrapPositionedRef <$> refs)) qual prettyPrintImport' (Import mn idt qual) = "import " <> P.prettyPrintImport mn idt qual
src/Language/PureScript/Ide/Pursuit.hs view
@@ -29,14 +29,11 @@ import Pipes.HTTP import qualified Pipes.Prelude as P --- We need to remove trailing dots because Pursuit will return a 400 otherwise--- TODO: remove this when the issue is fixed at Pursuit queryPursuit :: Text -> IO ByteString queryPursuit q = do- let qClean = T.dropWhileEnd (== '.') q req' <- parseRequest "https://pursuit.purescript.org/search" let req = req'- { queryString= "q=" <> (fromString . T.unpack) qClean+ { queryString= "q=" <> (fromString . T.unpack) q , requestHeaders=[(hAccept, "application/json")] } m <- newManager tlsManagerSettings@@ -45,7 +42,6 @@ handler :: HttpException -> IO [a]-handler StatusCodeException{} = pure [] handler _ = pure [] searchPursuitForDeclarations :: Text -> IO [PursuitResponse]
src/Language/PureScript/Ide/Rebuild.hs view
@@ -15,12 +15,13 @@ import Data.Maybe (fromJust) import qualified Data.Set as S import qualified Language.PureScript as P-import Language.PureScript.Errors.JSON import Language.PureScript.Ide.Error import Language.PureScript.Ide.Logging import Language.PureScript.Ide.State import Language.PureScript.Ide.Types import Language.PureScript.Ide.Util+import System.Directory (getCurrentDirectory)+import System.FilePath (makeRelative) -- | Given a filepath performs the following steps: --@@ -47,12 +48,11 @@ rebuildFile path runOpenBuild = do input <- ideReadFile path+ pwd <- liftIO getCurrentDirectory - m <- case snd <$> P.parseModuleFromFile identity (path, input) of- Left parseError -> throwError- . RebuildError- . toJSONErrors False P.Error- $ P.MultipleErrors [P.toPositionedError parseError]+ m <- case snd <$> P.parseModuleFromFile (makeRelative pwd) (path, input) of+ Left parseError ->+ throwError (RebuildError (P.MultipleErrors [P.toPositionedError parseError])) Right m -> pure m -- Externs files must be sorted ahead of time, so that they get applied@@ -74,10 +74,10 @@ . P.rebuildModule (buildMakeActions >>= shushProgress $ makeEnv) externs $ m case result of- Left errors -> throwError (RebuildError (toJSONErrors False P.Error errors))+ Left errors -> throwError (RebuildError errors) Right _ -> do runOpenBuild (rebuildModuleOpen makeEnv externs m)- pure (RebuildSuccess (toJSONErrors False P.Warning warnings))+ pure (RebuildSuccess warnings) rebuildFileAsync :: forall m. (Ide m, MonadLogger m, MonadError IdeError m)@@ -171,7 +171,7 @@ . M.delete (P.getModuleName m) $ ex case sorted' of Left err ->- throwError (RebuildError (toJSONErrors False P.Error err))+ throwError (RebuildError err) Right (sorted, graph) -> do let deps = fromJust (List.lookup (P.getModuleName m) graph) pure $ mapMaybe getExtern (deps `inOrderOf` map P.getModuleName sorted)
src/Language/PureScript/Ide/Reexports.hs view
@@ -68,21 +68,24 @@ resolveReexports reexportRefs modules = Map.mapWithKey (\moduleName decls -> maybe (ReexportResult decls [])- (resolveReexports' modules decls)+ (map (decls <>) . resolveReexports' modules) (Map.lookup moduleName reexportRefs)) modules resolveReexports' :: ModuleMap [IdeDeclarationAnn]- -> [IdeDeclarationAnn] -> [(P.ModuleName, P.DeclarationRef)] -> ReexportResult [IdeDeclarationAnn]-resolveReexports' modules decls refs =- ReexportResult (decls <> concat resolvedRefs) failedRefs+resolveReexports' modules refs =+ ReexportResult (concat resolvedRefs) failedRefs where (failedRefs, resolvedRefs) = partitionEithers (resolveRef' <$> refs) resolveRef' x@(mn, r) = case Map.lookup mn modules of Nothing -> Left x- Just decls' -> first (mn,) (resolveRef decls' r)+ Just decls' ->+ let+ setExportedFrom = set (idaAnnotation.annExportedFrom) . Just+ in+ bimap (mn,) (map (setExportedFrom mn)) (resolveRef decls' r) resolveRef :: [IdeDeclarationAnn]
src/Language/PureScript/Ide/SourceFile.hs view
@@ -14,7 +14,6 @@ module Language.PureScript.Ide.SourceFile ( parseModule- , getImportsForFile , extractAstInformation -- for tests , extractSpans@@ -28,42 +27,19 @@ import Language.PureScript.Ide.Error import Language.PureScript.Ide.Types import Language.PureScript.Ide.Util+import System.Directory (getCurrentDirectory)+import System.FilePath (makeRelative) parseModule :: (MonadIO m, MonadError IdeError m) => FilePath -> m (Either FilePath (FilePath, P.Module)) parseModule path = do+ pwd <- liftIO getCurrentDirectory contents <- ideReadFile path- case P.parseModuleFromFile identity (path, contents) of+ case P.parseModuleFromFile (makeRelative pwd) (path, contents) of Left _ -> pure (Left path) Right m -> pure (Right m)--getImports :: P.Module -> [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)]-getImports (P.Module _ _ _ declarations _) =- mapMaybe isImport declarations- where- isImport (P.PositionedDeclaration _ _ (P.ImportDeclaration a b c)) = Just (a, b, c)- isImport _ = Nothing--getImportsForFile :: (MonadIO m, MonadError IdeError m) =>- FilePath -> m [ModuleImport]-getImportsForFile fp = do- moduleE <- parseModule fp- case moduleE of- Left _ -> throwError (GeneralError "Failed to parse sourcefile.")- Right (_, module') ->- pure (mkModuleImport . unwrapPositionedImport <$> getImports module')- where- mkModuleImport (mn, importType', qualifier) =- ModuleImport- (P.runModuleName mn)- importType'- (P.runModuleName <$> qualifier)- unwrapPositionedImport (mn, it, q) = (mn, unwrapImportType it, q)- unwrapImportType (P.Explicit decls) = P.Explicit (map unwrapPositionedRef decls)- unwrapImportType (P.Hiding decls) = P.Hiding (map unwrapPositionedRef decls)- unwrapImportType P.Implicit = P.Implicit -- | Extracts AST information from a parsed module extractAstInformation
src/Language/PureScript/Ide/Types.hs view
@@ -106,11 +106,12 @@ data Annotation = Annotation- { annLocation :: Maybe P.SourceSpan- , annExportedFrom :: Maybe P.ModuleName- , annTypeAnnotation :: Maybe P.Type+ { _annLocation :: Maybe P.SourceSpan+ , _annExportedFrom :: Maybe P.ModuleName+ , _annTypeAnnotation :: Maybe P.Type } deriving (Show, Eq, Ord) +makeLenses ''Annotation makeLenses ''IdeDeclarationAnn emptyAnn :: Annotation@@ -184,7 +185,7 @@ , complExpandedType :: Text , complLocation :: Maybe P.SourceSpan , complDocumentation :: Maybe Text- } deriving (Show, Eq)+ } deriving (Show, Eq, Ord) instance ToJSON Completion where toJSON (Completion {..}) =@@ -196,34 +197,6 @@ , "documentation" .= complDocumentation ] -data ModuleImport =- ModuleImport- { importModuleName :: ModuleIdent- , importType :: P.ImportDeclarationType- , importQualifier :: Maybe Text- } deriving(Show)--instance Eq ModuleImport where- mi1 == mi2 =- importModuleName mi1 == importModuleName mi2- && importQualifier mi1 == importQualifier mi2--instance ToJSON ModuleImport where- toJSON (ModuleImport mn P.Implicit qualifier) =- object $ [ "module" .= mn- , "importType" .= ("implicit" :: Text)- ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)- toJSON (ModuleImport mn (P.Explicit refs) qualifier) =- object $ [ "module" .= mn- , "importType" .= ("explicit" :: Text)- , "identifiers" .= (identifierFromDeclarationRef <$> refs)- ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)- toJSON (ModuleImport mn (P.Hiding refs) qualifier) =- object $ [ "module" .= mn- , "importType" .= ("hiding" :: Text)- , "identifiers" .= (identifierFromDeclarationRef <$> refs)- ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)- identifierFromDeclarationRef :: P.DeclarationRef -> Text identifierFromDeclarationRef (P.TypeRef name _) = P.runProperName name identifierFromDeclarationRef (P.ValueRef ident) = P.runIdent ident@@ -238,10 +211,10 @@ | TextResult Text | MultilineTextResult [Text] | PursuitResult [PursuitResponse]- | ImportList [ModuleImport]+ | ImportList (P.ModuleName, [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)]) | ModuleList [ModuleIdent]- | RebuildSuccess [P.JSONError]- deriving (Show, Eq)+ | RebuildSuccess P.MultipleErrors+ deriving (Show) encodeSuccess :: (ToJSON a) => a -> Value encodeSuccess res =@@ -252,9 +225,28 @@ toJSON (TextResult t) = encodeSuccess t toJSON (MultilineTextResult ts) = encodeSuccess ts toJSON (PursuitResult resp) = encodeSuccess resp- toJSON (ImportList decls) = encodeSuccess decls+ toJSON (ImportList (moduleName, imports)) = object [ "resultType" .= ("success" :: Text)+ , "result" .= object [ "imports" .= map encodeImport imports+ , "moduleName" .= moduleName]] toJSON (ModuleList modules) = encodeSuccess modules- toJSON (RebuildSuccess modules) = encodeSuccess modules+ toJSON (RebuildSuccess warnings) = encodeSuccess (P.toJSONErrors False P.Warning warnings)++encodeImport :: (P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName) -> Value+encodeImport (P.runModuleName -> mn, importType, map P.runModuleName -> qualifier) = case importType of+ P.Implicit ->+ object $ [ "module" .= mn+ , "importType" .= ("implicit" :: Text)+ ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)+ P.Explicit refs ->+ object $ [ "module" .= mn+ , "importType" .= ("explicit" :: Text)+ , "identifiers" .= (identifierFromDeclarationRef <$> refs)+ ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)+ P.Hiding refs ->+ object $ [ "module" .= mn+ , "importType" .= ("hiding" :: Text)+ , "identifiers" .= (identifierFromDeclarationRef <$> refs)+ ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier) newtype PursuitQuery = PursuitQuery Text deriving (Show, Eq)
src/Language/PureScript/Ide/Util.hs view
@@ -24,7 +24,6 @@ , withEmptyAnn , valueOperatorAliasT , typeOperatorAliasT- , prettyTypeT , properNameT , identT , opNameT@@ -41,10 +40,10 @@ import qualified Data.Text.Lazy as TL import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8) import qualified Language.PureScript as P-import Language.PureScript.Ide.Error+import Language.PureScript.Ide.Error (prettyPrintTypeSingleLine, IdeError(..)) import Language.PureScript.Ide.Logging import Language.PureScript.Ide.Types-import System.IO.UTF8 (readUTF8FileT)+import System.IO.UTF8 (readUTF8FileT) identifierFromIdeDeclaration :: IdeDeclaration -> Text identifierFromIdeDeclaration d = case d of@@ -71,22 +70,22 @@ Completion {..} where (complIdentifier, complExpandedType) = case decl of- IdeDeclValue v -> (v ^. ideValueIdent . identT, v ^. ideValueType & prettyTypeT)+ IdeDeclValue v -> (v ^. ideValueIdent . identT, v ^. ideValueType & prettyPrintTypeSingleLine) IdeDeclType t -> (t ^. ideTypeName . properNameT, t ^. ideTypeKind & P.prettyPrintKind)- IdeDeclTypeSynonym s -> (s ^. ideSynonymName . properNameT, s ^. ideSynonymType & prettyTypeT)- IdeDeclDataConstructor d -> (d ^. ideDtorName . properNameT, d ^. ideDtorType & prettyTypeT)+ IdeDeclTypeSynonym s -> (s ^. ideSynonymName . properNameT, s ^. ideSynonymType & prettyPrintTypeSingleLine)+ IdeDeclDataConstructor d -> (d ^. ideDtorName . properNameT, d ^. ideDtorType & prettyPrintTypeSingleLine) IdeDeclTypeClass d -> (d ^. ideTCName . properNameT, "type class") IdeDeclValueOperator (IdeValueOperator op ref precedence associativity typeP) ->- (P.runOpName op, maybe (showFixity precedence associativity (valueOperatorAliasT ref) op) prettyTypeT typeP)+ (P.runOpName op, maybe (showFixity precedence associativity (valueOperatorAliasT ref) op) prettyPrintTypeSingleLine typeP) IdeDeclTypeOperator (IdeTypeOperator op ref precedence associativity kind) -> (P.runOpName op, maybe (showFixity precedence associativity (typeOperatorAliasT ref) op) P.prettyPrintKind kind) IdeDeclKind k -> (P.runProperName k, "kind") complModule = P.runModuleName m - complType = maybe complExpandedType prettyTypeT (annTypeAnnotation ann)+ complType = maybe complExpandedType prettyPrintTypeSingleLine (_annTypeAnnotation ann) - complLocation = annLocation ann+ complLocation = _annLocation ann complDocumentation = Nothing @@ -137,11 +136,3 @@ (\_ -> throwError (GeneralError ("Couldn't find file at: " <> T.pack fp))) pure contents--prettyTypeT :: P.Type -> Text-prettyTypeT =- T.unwords- . map T.strip- . T.lines- . T.pack- . P.prettyPrintTypeWithUnicode
src/Language/PureScript/Interactive.hs view
@@ -11,8 +11,9 @@ import Prelude () import Prelude.Compat+import Protolude (ordNub) -import Data.List (nub, sort, find, foldl')+import Data.List (sort, find, foldl') import Data.Maybe (mapMaybe) import qualified Data.Map as M import Data.Monoid ((<>))@@ -94,7 +95,8 @@ -> Command -> m () handleCommand _ _ ShowHelp = liftIO $ putStrLn helpMessage-handleCommand _ r ResetState = handleResetState r+handleCommand _ r ReloadState = handleReloadState r+handleCommand _ r ClearState = handleClearState r handleCommand c _ (Expression val) = handleExpression c val handleCommand _ _ (Import im) = handleImport im handleCommand _ _ (Decls l) = handleDecls l@@ -105,14 +107,13 @@ handleCommand _ _ (ShowInfo QueryImport) = handleShowImportedModules handleCommand _ _ _ = P.internalError "handleCommand: unexpected command" --- | Reset the application state-handleResetState+-- | Reload the application state+handleReloadState :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m) => m () -> m ()-handleResetState reload = do- modify $ updateImportedModules (const [])- . updateLets (const [])+handleReloadState reload = do+ modify $ updateLets (const []) files <- asks psciLoadedFiles e <- runExceptT $ do modules <- ExceptT . liftIO $ loadAllModules files@@ -124,6 +125,15 @@ modify (updateLoadedExterns (const (zip modules externs))) reload +-- | Clear the application state+handleClearState+ :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)+ => m ()+ -> m ()+handleClearState reload = do+ modify $ updateImportedModules (const [])+ handleReloadState reload+ -- | Takes a value expression and evaluates it with the current state. handleExpression :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)@@ -164,7 +174,7 @@ loadedModules <- gets psciLoadedExterns liftIO $ putStrLn (readModules loadedModules) where- readModules = unlines . sort . nub . map (T.unpack . P.runModuleName . P.getModuleName . fst)+ readModules = unlines . sort . ordNub . map (T.unpack . P.runModuleName . P.getModuleName . fst) -- | Show the imported modules in psci. handleShowImportedModules
src/Language/PureScript/Interactive/Completion.hs view
@@ -6,13 +6,14 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Arrow (second) import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.State.Class (MonadState(..)) import Control.Monad.Trans.Reader (asks, runReaderT, ReaderT) import Data.Function (on)-import Data.List (nub, nubBy, isPrefixOf, sortBy, stripPrefix)+import Data.List (nubBy, isPrefixOf, sortBy, stripPrefix) import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T@@ -120,7 +121,8 @@ directiveArg :: String -> Directive -> [CompletionContext] directiveArg _ Browse = [CtxModule] directiveArg _ Quit = []-directiveArg _ Reset = []+directiveArg _ Reload = []+directiveArg _ Clear = [] directiveArg _ Help = [] directiveArg _ Paste = [] directiveArg _ Show = map CtxFixed replQueryStrings@@ -169,7 +171,7 @@ getAllQualifications sho m (declName, decl) = do imports <- getAllImportsOf m let fullyQualified = qualifyWith (Just (P.getModuleName m))- let otherQuals = nub (concatMap qualificationsUsing imports)+ let otherQuals = ordNub (concatMap qualificationsUsing imports) return $ fullyQualified : otherQuals where qualifyWith mMod = T.unpack (P.showQualified sho (P.Qualified mMod declName))@@ -220,4 +222,4 @@ go _ = [] moduleNames :: [P.Module] -> [String]-moduleNames = nub . map (T.unpack . P.runModuleName . P.getModuleName)+moduleNames = ordNub . map (T.unpack . P.runModuleName . P.getModuleName)
src/Language/PureScript/Interactive/Directive.hs view
@@ -25,7 +25,8 @@ directiveStrings = [ (Help , ["?", "help"]) , (Quit , ["quit"])- , (Reset , ["reset"])+ , (Reload , ["reload"])+ , (Clear , ["clear"]) , (Browse , ["browse"]) , (Type , ["type"]) , (Kind , ["kind"])@@ -82,7 +83,8 @@ hasArgument :: Directive -> Bool hasArgument Help = False hasArgument Quit = False-hasArgument Reset = False+hasArgument Reload = False+hasArgument Clear = False hasArgument Paste = False hasArgument _ = True @@ -93,7 +95,8 @@ help = [ (Help, "", "Show this help menu") , (Quit, "", "Quit PSCi")- , (Reset, "", "Discard all imported modules and declared bindings")+ , (Reload, "", "Reload all imported modules while discarding bindings")+ , (Clear, "", "Discard all imported modules and declared bindings") , (Browse, "<module>", "See all functions in <module>") , (Type, "<expr>", "Show the type of <expr>") , (Kind, "<type>", "Show the kind of <type>")
src/Language/PureScript/Interactive/Message.hs view
@@ -10,6 +10,10 @@ -- Messages +-- | The guide URL+guideURL :: String+guideURL = "https://github.com/purescript/documentation/blob/master/guides/PSCi.md"+ -- | The help message. helpMessage :: String helpMessage = "The following commands are available:\n\n " ++@@ -28,7 +32,7 @@ extraHelp = "Further information is available on the PureScript documentation repository:\n" ++- " --> https://github.com/purescript/documentation/blob/master/PSCi.md"+ " --> " ++ guideURL -- | The welcome prologue. prologueMessage :: String@@ -37,18 +41,17 @@ , "Type :? for help" ] +noInputMessage :: String+noInputMessage = unlines+ [ "purs repl: No input files; try running `pulp psci` instead."+ , "For help getting started, visit " ++ guideURL+ , "Usage: For basic information, try the `--help' option."+ ]+ supportModuleMessage :: String supportModuleMessage = unlines- [ "PSCi requires the psci-support package to be installed."- , "You can install it using Bower as follows:"- , ""- , " bower i purescript-psci-support --save-dev"- , ""- , "Or using psc-package:"- , ""- , " psc-package install psci-support"- , ""- , "For help getting started, visit https://github.com/purescript/documentation/blob/master/PSCi.md"+ [ "purs repl: PSCi requires the psci-support package."+ , "For help getting started, visit " ++ guideURL ] -- | The quit message.
src/Language/PureScript/Interactive/Module.hs view
@@ -5,7 +5,8 @@ import Control.Monad import qualified Language.PureScript as P import Language.PureScript.Interactive.Types-import System.FilePath (pathSeparator)+import System.Directory (getCurrentDirectory)+import System.FilePath (pathSeparator, makeRelative) import System.IO.UTF8 (readUTF8FileT) -- * Support Module@@ -20,23 +21,23 @@ -- * Module Management --- |--- Loads a file for use with imports.---+-- | Loads a file for use with imports. loadModule :: FilePath -> IO (Either String [P.Module]) loadModule filename = do+ pwd <- getCurrentDirectory content <- readUTF8FileT filename- return $ either (Left . P.prettyPrintMultipleErrors P.defaultPPEOptions) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]+ return $+ either (Left . P.prettyPrintMultipleErrors P.defaultPPEOptions) (Right . map snd) $+ P.parseModulesFromFiles (makeRelative pwd) [(filename, content)] --- |--- Load all modules.---+-- | Load all modules. loadAllModules :: [FilePath] -> IO (Either P.MultipleErrors [(FilePath, P.Module)]) loadAllModules files = do+ pwd <- getCurrentDirectory filesAndContent <- forM files $ \filename -> do content <- readUTF8FileT filename return (filename, content)- return $ P.parseModulesFromFiles id filesAndContent+ return $ P.parseModulesFromFiles (makeRelative pwd) filesAndContent -- | -- Makes a volatile module to execute the current expression.@@ -50,7 +51,7 @@ supportImport = (supportModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Support"])) eval = P.Var (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval")) mainValue = P.App eval (P.Var (P.Qualified Nothing (P.Ident "it")))- itDecl = P.ValueDeclaration (P.Ident "it") P.Public [] $ Right val+ itDecl = P.ValueDeclaration (P.Ident "it") P.Public [] [P.MkUnguarded val] typeDecl = P.TypeDeclaration (P.Ident "$main") (P.TypeApp (P.TypeApp@@ -58,7 +59,7 @@ (P.Qualified (Just (P.ModuleName [P.ProperName "$Eff"])) (P.ProperName "Eff"))) (P.TypeWildcard internalSpan)) (P.TypeWildcard internalSpan))- mainDecl = P.ValueDeclaration (P.Ident "$main") P.Public [] $ Right mainValue+ mainDecl = P.ValueDeclaration (P.Ident "$main") P.Public [] [P.MkUnguarded mainValue] decls = if exec then [itDecl, typeDecl, mainDecl] else [itDecl] internalSpan = P.internalModuleSourceSpan "<internal>" in
src/Language/PureScript/Interactive/Parser.hs view
@@ -7,6 +7,7 @@ import Prelude.Compat hiding (lex) +import Data.Bifunctor (first) import Data.Char (isSpace) import Data.List (intercalate) import qualified Data.Text as T@@ -26,7 +27,7 @@ _ -> parseRest psciCommand cmdString parseRest :: P.TokenParser a -> String -> Either String a-parseRest p s = either (Left . show) Right $ do+parseRest p s = first show $ do ts <- P.lex "" (T.pack s) P.runTokenParser "" (p <* eof) ts @@ -34,10 +35,10 @@ psciCommand = choice (map try parsers) where parsers =- [ psciLet- , psciImport- , psciOtherDeclaration+ [ psciImport+ , psciDeclaration , psciExpression+ , psciDeprecatedLet ] trim :: String -> String@@ -62,7 +63,8 @@ commandFor d = case d of Help -> return ShowHelp Quit -> return QuitPSCi- Reset -> return ResetState+ Reload -> return ReloadState+ Clear -> return ClearState Paste -> return PasteLines Browse -> BrowseModule <$> parseRest P.moduleName arg Show -> ShowInfo <$> parseReplQuery' (trim arg)@@ -75,18 +77,6 @@ psciExpression :: P.TokenParser Command psciExpression = Expression <$> P.parseValue --- |--- PSCI version of @let@.--- This is essentially let from do-notation.--- However, since we don't support the @Eff@ monad,--- we actually want the normal @let@.----psciLet :: P.TokenParser Command-psciLet = Decls <$> (P.reserved "let" *> P.indented *> manyDecls)- where- manyDecls :: P.TokenParser [P.Declaration]- manyDecls = mark (many1 (same *> P.parseLocalDeclaration))- -- | Imports must be handled separately from other declarations, so that -- :show import works, for example. psciImport :: P.TokenParser Command@@ -94,10 +84,10 @@ (mn, declType, asQ) <- P.parseImportDeclaration' return $ Import (mn, declType, asQ) --- | Any other declaration that we don't need a 'special case' parser for--- (like let or import declarations).-psciOtherDeclaration :: P.TokenParser Command-psciOtherDeclaration = Decls . (:[]) <$> do+-- | Any declaration that we don't need a 'special case' parser for+-- (like import declarations).+psciDeclaration :: P.TokenParser Command+psciDeclaration = fmap Decls $ mark $ many1 $ same *> do decl <- discardPositionInfo <$> P.parseDeclaration if acceptable decl then return decl@@ -115,6 +105,8 @@ acceptable P.TypeClassDeclaration{} = True acceptable P.TypeInstanceDeclaration{} = True acceptable P.ExternKindDeclaration{} = True+acceptable P.TypeDeclaration{} = True+acceptable P.ValueDeclaration{} = True acceptable _ = False parseReplQuery' :: String -> Either String ReplQuery@@ -123,3 +115,13 @@ Nothing -> Left ("Don't know how to show " ++ str ++ ". Try one of: " ++ intercalate ", " replQueryStrings ++ ".") Just query -> Right query++-- | To show error message when 'let' is used for declaration in PSCI,+-- which is deprecated.+psciDeprecatedLet :: P.TokenParser Command+psciDeprecatedLet = do+ P.reserved "let"+ P.indented+ _ <- mark (many1 (same *> P.parseLocalDeclaration))+ notFollowedBy $ P.reserved "in"+ fail "Declarations in PSCi no longer require \"let\", as of version 0.11.0"
src/Language/PureScript/Interactive/Types.hs view
@@ -82,8 +82,10 @@ | BrowseModule P.ModuleName -- | Exit PSCI | QuitPSCi- -- | Reset the state of the REPL- | ResetState+ -- | Reload all the imported modules of the REPL+ | ReloadState+ -- | Clear the state of the REPL+ | ClearState -- | Add some declarations to the current evaluation context | Decls [P.Declaration] -- | Find the type of an expression@@ -94,6 +96,7 @@ | ShowInfo ReplQuery -- | Paste multiple lines | PasteLines+ deriving Show data ReplQuery = QueryLoaded@@ -119,7 +122,8 @@ data Directive = Help | Quit- | Reset+ | Reload+ | Clear | Browse | Type | Kind
src/Language/PureScript/Kinds.hs view
@@ -52,8 +52,6 @@ KUnknown <$> key "contents" (nth 0 asIntegral) "Star" -> pure kindType- "Bang" ->- pure kindEffect "Row" -> Row <$> key "contents" kindFromJSON "FunKind" ->@@ -78,7 +76,6 @@ primKind = NamedKind . primName kindType = primKind "Type"- kindEffect = primKind "Effect" kindSymbol = primKind "Symbol" instance A.FromJSON Kind where
src/Language/PureScript/Linter.hs view
@@ -4,10 +4,11 @@ module Language.PureScript.Linter (lint, module L) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad.Writer.Class -import Data.List (nub, (\\))+import Data.List ((\\)) import Data.Maybe (mapMaybe) import Data.Monoid import qualified Data.Set as S@@ -28,7 +29,7 @@ lint (Module _ _ mn ds _) = censor (addHint (ErrorInModule mn)) $ mapM_ lintDeclaration ds where moduleNames :: S.Set Ident- moduleNames = S.fromList (nub (mapMaybe getDeclIdent ds))+ moduleNames = S.fromList (ordNub (mapMaybe getDeclIdent ds)) getDeclIdent :: Declaration -> Maybe Ident getDeclIdent (PositionedDeclaration _ _ d) = getDeclIdent d@@ -55,7 +56,7 @@ f' s dec = warningsInDecl moduleNames dec <> checkTypeVarsInDecl s dec stepE :: S.Set Ident -> Expr -> MultipleErrors- stepE s (Abs (Left name) _) | name `S.member` s = errorMessage (ShadowedName name)+ stepE s (Abs (VarBinder name) _) | name `S.member` s = errorMessage (ShadowedName name) stepE s (Let ds' _) = foldMap go ds' where go d | Just i <- getDeclIdent d@@ -91,7 +92,7 @@ findUnused ty' = let used = usedTypeVariables ty' declared = everythingOnTypes (++) go ty'- unused = nub declared \\ nub used+ unused = ordNub declared \\ ordNub used in foldl (<>) mempty $ map (errorMessage . UnusedTypeVar) unused where go :: Type -> [Text]
src/Language/PureScript/Linter/Exhaustive.hs view
@@ -9,6 +9,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Applicative import Control.Arrow (first, second)@@ -17,7 +18,7 @@ import Control.Monad.Supply.Class (MonadSupply, fresh, freshName) import Data.Function (on)-import Data.List (foldl', sortBy, nub)+import Data.List (foldl', sortBy) import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import qualified Data.Map as M@@ -202,18 +203,18 @@ -- The function below say whether or not a guard has an `otherwise` expression -- It is considered that `otherwise` is defined in Prelude ---isExhaustiveGuard :: Either [(Guard, Expr)] Expr -> Bool-isExhaustiveGuard (Left gs) = not . null $ filter (\(g, _) -> isOtherwise g) gs+isExhaustiveGuard :: [GuardedExpr] -> Bool+isExhaustiveGuard [GuardedExpr [] _] = True+isExhaustiveGuard gs =+ not . null $ filter (\(GuardedExpr grd _) -> isExhaustive grd) gs where- isOtherwise :: Expr -> Bool- isOtherwise (Literal (BooleanLiteral True)) = True- isOtherwise (Var (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) = True- isOtherwise (Var (Qualified (Just (ModuleName [ProperName "Data", ProperName "Boolean"])) (Ident "otherwise"))) = True- isOtherwise (TypedValue _ e _) = isOtherwise e- isOtherwise (PositionedValue _ _ e) = isOtherwise e- isOtherwise _ = False-isExhaustiveGuard (Right _) = True+ checkGuard :: Guard -> Bool+ checkGuard (ConditionGuard cond) = isTrueExpr cond+ checkGuard (PatternGuard bind _) = isIrrefutable bind + isExhaustive :: [Guard] -> Bool+ isExhaustive = all checkGuard+ -- | -- Returns the uncovered set of case alternatives --@@ -242,12 +243,12 @@ -> [CaseAlternative] -> Expr -> m Expr-checkExhaustive env mn numArgs cas expr = makeResult . first nub $ foldl' step ([initialize numArgs], (pure True, [])) cas+checkExhaustive env mn numArgs cas expr = makeResult . first ordNub $ foldl' step ([initialize numArgs], (pure True, [])) cas where step :: ([[Binder]], (Either RedundancyError Bool, [[Binder]])) -> CaseAlternative -> ([[Binder]], (Either RedundancyError Bool, [[Binder]])) step (uncovered, (nec, redundant)) ca = let (missed, pr) = unzip (map (missingAlternative env mn ca) uncovered)- (missed', approx) = splitAt 10000 (nub (concat missed))+ (missed', approx) = splitAt 10000 (ordNub (concat missed)) cond = or <$> sequenceA pr in (missed', ( if null approx then liftA2 (&&) cond nec@@ -288,17 +289,19 @@ where partial :: Text -> Text -> Declaration partial var tyVar =- ValueDeclaration (Ident C.__unused) Private [] $ Right $- TypedValue- True- (Abs (Left (Ident var)) (Var (Qualified Nothing (Ident var))))- (ty tyVar)+ ValueDeclaration (Ident C.__unused) Private [] $+ [MkUnguarded+ (TypedValue+ True+ (Abs (VarBinder (Ident var)) (Var (Qualified Nothing (Ident var))))+ (ty tyVar))+ ] ty :: Text -> Type ty tyVar = ForAll tyVar ( ConstrainedType- [ Constraint C.Partial [] (Just constraintData) ]+ (Constraint C.Partial [] (Just constraintData)) $ TypeApp (TypeApp tyFunction (TypeVar tyVar)) (TypeVar tyVar) ) Nothing@@ -321,7 +324,7 @@ where onDecl :: Declaration -> m Declaration onDecl (BindingGroupDeclaration bs) = BindingGroupDeclaration <$> mapM (thirdM onExpr) bs- onDecl (ValueDeclaration name x y (Right e)) = ValueDeclaration name x y . Right <$> censor (addHint (ErrorInValueDeclaration name)) (onExpr e)+ onDecl (ValueDeclaration name x y [MkUnguarded e]) = ValueDeclaration name x y . mkUnguardedExpr <$> censor (addHint (ErrorInValueDeclaration name)) (onExpr e) onDecl (PositionedDeclaration pos x dec) = PositionedDeclaration pos x <$> censor (addHint (PositionedError pos)) (onDecl dec) onDecl decl = return decl @@ -344,5 +347,10 @@ onExpr expr = return expr onCaseAlternative :: CaseAlternative -> m CaseAlternative- onCaseAlternative (CaseAlternative x (Left es)) = CaseAlternative x . Left <$> mapM (\(e, g) -> (,) <$> onExpr e <*> onExpr g) es- onCaseAlternative (CaseAlternative x (Right e)) = CaseAlternative x . Right <$> onExpr e+ onCaseAlternative (CaseAlternative x [MkUnguarded e]) = CaseAlternative x . mkUnguardedExpr <$> onExpr e+ onCaseAlternative (CaseAlternative x es) = CaseAlternative x <$> mapM onGuardedExpr es++ onGuardedExpr :: GuardedExpr -> m GuardedExpr+ onGuardedExpr (GuardedExpr guard rhs) = GuardedExpr guard <$> onExpr rhs++ mkUnguardedExpr = pure . MkUnguarded
src/Language/PureScript/Linter/Imports.hs view
@@ -5,13 +5,14 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad (join, unless, foldM, (<=<)) import Control.Monad.Writer.Class import Data.Function (on) import Data.Foldable (for_)-import Data.List (find, intersect, nub, groupBy, sortBy, (\\))+import Data.List (find, intersect, groupBy, sortBy, (\\)) import Data.Maybe (mapMaybe, fromMaybe) import Data.Monoid (Sum(..)) import Data.Traversable (forM)@@ -71,16 +72,16 @@ unless (isPrim mni) $ for_ decls $ \(ss', declType, qualifierName) -> maybe id warnWithPosition ss' $ do- let names = nub $ M.findWithDefault [] mni usedImps'+ let names = ordNub $ M.findWithDefault [] mni usedImps' lintImportDecl env mni qualifierName names declType allowImplicit for_ (M.toAscList (byQual imports)) $ \(mnq, entries) -> do- let mnis = nub $ map (\(_, _, mni) -> mni) entries+ let mnis = ordNub $ map (\(_, _, mni) -> mni) entries unless (length mnis == 1) $ do let implicits = filter (\(_, declType, _) -> not $ isExplicit declType) entries for_ implicits $ \(ss', _, mni) -> maybe id warnWithPosition ss' $ do- let names = nub $ M.findWithDefault [] mni usedImps'+ let names = ordNub $ M.findWithDefault [] mni usedImps' usedRefs = findUsedRefs env mni (Just mnq) names unless (null usedRefs) $ tell $ errorMessage $ ImplicitQualifiedImport mni mnq usedRefs@@ -147,7 +148,7 @@ -- The list of modules that are being re-exported by the current module. Any -- module that appears in this list is always considered to be used. exportedModules :: [ModuleName]- exportedModules = nub $ mapMaybe extractModule mexports+ exportedModules = ordNub $ mapMaybe extractModule mexports where extractModule (PositionedDeclarationRef _ _ r) = extractModule r extractModule (ModuleRef mne) = Just mne@@ -231,7 +232,7 @@ :: [DeclarationRef] -> m Bool checkExplicit declrefs = do- let idents = nub (mapMaybe runDeclRef declrefs)+ let idents = ordNub (mapMaybe runDeclRef declrefs) dctors = mapMaybe (getDctorName <=< disqualifyFor qualifierName) names usedNames = mapMaybe (matchName (typeForDCtor mni) <=< disqualifyFor qualifierName) names diff = idents \\ usedNames
src/Language/PureScript/Make.hs view
@@ -60,17 +60,18 @@ import Language.PureScript.ModuleDependencies import Language.PureScript.Names import Language.PureScript.Options-import Language.PureScript.Pretty-import Language.PureScript.Pretty.Common(SMap(..))+import Language.PureScript.Pretty.Common (SMap(..)) import Language.PureScript.Renamer import Language.PureScript.Sugar import Language.PureScript.TypeChecker import qualified Language.JavaScript.Parser as JS import qualified Language.PureScript.Bundle as Bundle import qualified Language.PureScript.CodeGen.JS as J+import Language.PureScript.CodeGen.JS.Printer import qualified Language.PureScript.Constants as C import qualified Language.PureScript.CoreFn as CF import qualified Language.PureScript.CoreFn.ToJSON as CFJ+import qualified Language.PureScript.CoreImp.AST as Imp import qualified Language.PureScript.Parser as PSParser import qualified Paths_purescript as Paths import SourceMap@@ -94,7 +95,7 @@ -- -- This type exists to make two things abstract: ----- * The particular backend being used (Javascript, C++11, etc.)+-- * The particular backend being used (JavaScript, C++11, etc.) -- -- * The details of how files are read/written etc. data MakeActions m = MakeActions@@ -351,7 +352,7 @@ return Nothing | otherwise -> do checkForeignDecls m path- return $ Just $ J.JSApp Nothing (J.JSVar Nothing "require") [J.JSStringLiteral Nothing "./foreign"]+ return $ Just $ Imp.App Nothing (Imp.Var Nothing "require") [Imp.StringLiteral Nothing "./foreign"] Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn | otherwise -> return Nothing rawJs <- J.moduleToJs m foreignInclude@@ -363,7 +364,7 @@ mapFile = outputDir </> filePath </> "index.js.map" externsFile = outputDir </> filePath </> "externs.json" foreignFile = outputDir </> filePath </> "foreign.js"- prefix = ["Generated by psc version " <> T.pack (showVersion Paths.version) | usePrefix]+ prefix = ["Generated by purs version " <> T.pack (showVersion Paths.version) | usePrefix] js = T.unlines $ map ("// " <>) prefix ++ [pjs] mapRef = if sourceMaps then "//# sourceMappingURL=index.js.map\n" else "" lift $ do
src/Language/PureScript/ModuleDependencies.hs view
@@ -27,8 +27,8 @@ -> m ([Module], ModuleGraph) sortModules ms = do let mns = S.fromList $ map getModuleName ms- verts <- mapM (toGraphNode mns) ms- ms' <- mapM toModule $ stronglyConnComp verts+ verts <- parU ms (toGraphNode mns)+ ms' <- parU (stronglyConnComp verts) toModule let (graph, fromVertex, toVertex) = graphFromEdges verts moduleGraph = do (_, mn, _) <- verts let v = fromMaybe (internalError "sortModules: vertex not found") (toVertex mn)@@ -39,23 +39,23 @@ where toGraphNode :: S.Set ModuleName -> Module -> m (Module, ModuleName, [ModuleName]) toGraphNode mns m@(Module _ _ mn ds _) = do- let deps = ordNub (concatMap usedModules ds)- forM_ deps $ \dep ->+ let deps = ordNub (mapMaybe usedModules ds)+ void . parU deps $ \(dep, pos) -> when (dep /= C.Prim && S.notMember dep mns) $- throwError . addHint (ErrorInModule mn) . errorMessage $ ModuleNotFound dep- pure (m, getModuleName m, deps)+ throwError+ . addHint (ErrorInModule mn)+ . maybe identity (addHint . PositionedError) pos+ . errorMessage+ $ ModuleNotFound dep+ pure (m, getModuleName m, map fst deps) -- | Calculate a list of used modules based on explicit imports and qualified names.-usedModules :: Declaration -> [ModuleName]-usedModules d = f d where- f :: Declaration -> [ModuleName]- (f, _, _, _, _) = everythingOnValues (++) forDecls (const []) (const []) (const []) (const [])-- forDecls :: Declaration -> [ModuleName]- -- Regardless of whether an imported module is qualified we still need to- -- take into account its import to build an accurate list of dependencies.- forDecls (ImportDeclaration mn _ _) = [mn]- forDecls _ = []+usedModules :: Declaration -> Maybe (ModuleName, Maybe SourceSpan)+-- Regardless of whether an imported module is qualified we still need to+-- take into account its import to build an accurate list of dependencies.+usedModules (ImportDeclaration mn _ _) = pure (mn, Nothing)+usedModules (PositionedDeclaration ss _ d) = fmap (second (const (Just ss))) (usedModules d)+usedModules _ = Nothing -- | Convert a strongly connected component of the module graph to a module toModule :: MonadError MultipleErrors m => SCC Module -> m Module
src/Language/PureScript/Names.hs view
@@ -25,7 +25,7 @@ | TyClassName (ProperName 'ClassName) | ModName ModuleName | KiName (ProperName 'KindName)- deriving (Eq, Show)+ deriving (Eq, Ord, Show) getIdentName :: Name -> Maybe Ident getIdentName (IdentName name) = Just name
src/Language/PureScript/Options.hs view
@@ -1,42 +1,20 @@--- |--- The data type of compiler options---+-- | The data type of compiler options module Language.PureScript.Options where import Prelude.Compat --- |--- The data type of compiler options----data Options = Options {- -- |- -- Disable tail-call elimination- optionsNoTco :: Bool- -- |- -- Disable inlining of calls to return and bind for the Eff monad- , optionsNoMagicDo :: Bool- -- |- -- When specified, checks the type of `main` in the module, and generate a call to run main- -- after the module definitions.- , optionsMain :: Maybe String- -- |- -- Skip all optimizations- , optionsNoOptimizations :: Bool- -- |- -- Verbose error message- , optionsVerboseErrors :: Bool- -- |- -- Remove the comments from the generated js+-- | The data type of compiler options+data Options = Options+ { optionsVerboseErrors :: Bool+ -- ^ Verbose error message , optionsNoComments :: Bool- -- |- -- Generate soure maps+ -- ^ Remove the comments from the generated js , optionsSourceMaps :: Bool- -- |- -- Dump CoreFn+ -- ^ Generate source maps , optionsDumpCoreFn :: Bool+ -- ^ Dump CoreFn } deriving Show --- | -- Default make options defaultOptions :: Options-defaultOptions = Options False False Nothing False False False False False+defaultOptions = Options False False False False
src/Language/PureScript/Parser.hs view
@@ -1,23 +1,23 @@--- | --- A collection of parsers for core data types: --- --- [@Language.PureScript.Parser.Kinds@] Parser for kinds --- --- [@Language.PureScript.Parser.Values@] Parser for values --- --- [@Language.PureScript.Parser.Types@] Parser for types --- --- [@Language.PureScript.Parser.Declaration@] Parsers for declarations and modules --- --- [@Language.PureScript.Parser.State@] Parser state, including indentation --- --- [@Language.PureScript.Parser.Common@] Common parsing utility functions --- -module Language.PureScript.Parser (module P) where - -import Language.PureScript.Parser.Common as P -import Language.PureScript.Parser.Declarations as P -import Language.PureScript.Parser.Kinds as P -import Language.PureScript.Parser.Lexer as P -import Language.PureScript.Parser.State as P -import Language.PureScript.Parser.Types as P +-- |+-- A collection of parsers for core data types:+--+-- [@Language.PureScript.Parser.Kinds@] Parser for kinds+--+-- [@Language.PureScript.Parser.Values@] Parser for values+--+-- [@Language.PureScript.Parser.Types@] Parser for types+--+-- [@Language.PureScript.Parser.Declaration@] Parsers for declarations and modules+--+-- [@Language.PureScript.Parser.State@] Parser state, including indentation+--+-- [@Language.PureScript.Parser.Common@] Common parsing utility functions+--+module Language.PureScript.Parser (module P) where++import Language.PureScript.Parser.Common as P+import Language.PureScript.Parser.Declarations as P+import Language.PureScript.Parser.Kinds as P+import Language.PureScript.Parser.Lexer as P+import Language.PureScript.Parser.State as P+import Language.PureScript.Parser.Types as P
src/Language/PureScript/Parser/Declarations.hs view
@@ -1,7 +1,9 @@ -- | Parsers for module definitions and declarations module Language.PureScript.Parser.Declarations ( parseDeclaration+ , parseDeclarationRef , parseModule+ , parseModuleDeclaration , parseModulesFromFiles , parseModuleFromFile , parseValue@@ -17,7 +19,7 @@ import Control.Applicative import Control.Arrow ((+++))-import Control.Monad (foldM)+import Control.Monad (foldM, join) import Control.Monad.Error.Class (MonadError(..)) import Control.Parallel.Strategies (withStrategy, parList, rseq) import Data.Functor (($>))@@ -63,27 +65,41 @@ <*> many (indented *> kindedIdent) <*> (indented *> equals *> noWildcards parsePolyType) +parseValueWithWhereClause :: TokenParser Expr+parseValueWithWhereClause = do+ indented+ value <- parseValue+ whereClause <- P.optionMaybe $ do+ indented+ reserved "where"+ indented+ mark $ P.many1 (same *> parseLocalDeclaration)+ return $ maybe value (`Let` value) whereClause++parseValueWithIdentAndBinders :: Ident -> [Binder] -> TokenParser Declaration+parseValueWithIdentAndBinders ident bs = do+ value <- indented *> (+ (\v -> [MkUnguarded v]) <$> (equals *> withSourceSpan PositionedValue parseValueWithWhereClause) <|>+ P.many1 (GuardedExpr <$> parseGuard+ <*> (indented *> equals+ *> withSourceSpan PositionedValue parseValueWithWhereClause))+ )+ return $ ValueDeclaration ident Public bs value+ parseValueDeclaration :: TokenParser Declaration parseValueDeclaration = do- name <- parseIdent+ ident <- parseIdent binders <- P.many parseBinderNoParens- value <- Left <$> (indented *>- P.many1 ((,) <$> parseGuard- <*> (indented *> equals *> parseValueWithWhereClause)- ))- <|> Right <$> (indented *> equals *> parseValueWithWhereClause)- return $ ValueDeclaration name Public binders value+ parseValueWithIdentAndBinders ident binders++parseLocalValueDeclaration :: TokenParser Declaration+parseLocalValueDeclaration = join $ go <$> parseBinder <*> (P.many parseBinderNoParens) where- parseValueWithWhereClause :: TokenParser Expr- parseValueWithWhereClause = do- indented- value <- parseValue- whereClause <- P.optionMaybe $ do- indented- reserved "where"- indented- mark $ P.many1 (same *> parseLocalDeclaration)- return $ maybe value (`Let` value) whereClause+ go :: Binder -> [Binder] -> TokenParser Declaration+ go (VarBinder ident) bs = parseValueWithIdentAndBinders ident bs+ go (PositionedBinder _ _ b) bs = go b bs+ go binder [] = BoundValueDeclaration binder <$> (indented *> equals *> parseValueWithWhereClause)+ go _ _ = P.unexpected $ "patterns in local value declaration" parseExternDeclaration :: TokenParser Declaration parseExternDeclaration = reserved "foreign" *> indented *> reserved "import" *> indented *> parseExternAlt where@@ -119,7 +135,7 @@ <*> (reserved "as" *> parseOperator) valueFixity fixity = ValueFixity fixity- <$> parseQualified ((Left <$> parseIdent) <|> (Right <$> properName))+ <$> parseQualified ((Left <$> parseIdent) <|> (Right <$> dataConstructorName)) <*> (reserved "as" *> parseOperator) parseImportDeclaration :: TokenParser Declaration@@ -154,7 +170,7 @@ where parseTypeRef = do name <- typeName- dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)+ dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep dataConstructorName) return $ TypeRef name (fromMaybe (Just []) dctors) parseTypeClassDeclaration :: TokenParser Declaration@@ -230,19 +246,25 @@ parseLocalDeclaration :: TokenParser Declaration parseLocalDeclaration = positioned (P.choice [ parseTypeDeclaration- , parseValueDeclaration+ , parseLocalValueDeclaration ] P.<?> "local declaration") --- | Parse a module header and a collection of declarations-parseModule :: TokenParser Module-parseModule = do- comments <- readComments- start <- P.getPosition+-- | Parse a module declaration and its export declarations+parseModuleDeclaration :: TokenParser (ModuleName, Maybe [DeclarationRef])+parseModuleDeclaration = do reserved "module" indented name <- moduleName exports <- P.optionMaybe $ parens $ commaSep1 parseDeclarationRef reserved "where"+ pure (name, exports)++-- | Parse a module header and a collection of declarations+parseModule :: TokenParser Module+parseModule = do+ comments <- readComments+ start <- P.getPosition+ (name, exports) <- parseModuleDeclaration decls <- mark $ do -- TODO: extract a module header structure here, and provide a -- parseModuleHeader function. This should allow us to speed up rebuilds@@ -326,7 +348,7 @@ parseAbs :: TokenParser Expr parseAbs = do symbol' "\\"- args <- P.many1 (indented *> (Abs <$> (Left <$> parseIdent <|> Right <$> parseBinderNoParens)))+ args <- P.many1 (indented *> (Abs <$> parseBinderNoParens)) indented *> rarrow value <- parseValue return $ toFunction args value@@ -346,11 +368,13 @@ parseCaseAlternative :: TokenParser CaseAlternative parseCaseAlternative = CaseAlternative <$> commaSep1 parseBinder- <*> (Left <$> (indented *>- P.many1 ((,) <$> parseGuard- <*> (indented *> rarrow *> parseValue)- ))- <|> Right <$> (indented *> rarrow *> parseValue))+ <*> (indented *> (+ (pure . MkUnguarded) <$> (rarrow *> parseValue)+ <|> (P.many1 (GuardedExpr <$> parseGuard+ <*> (indented+ *> rarrow+ *> parseValue)+ )))) P.<?> "case alternative" parseIfThenElse :: TokenParser Expr@@ -427,7 +451,7 @@ parseDoNotationBind = DoNotationBind <$> P.try (parseBinder <* indented <* larrow) <*> parseValue parseDoNotationElement :: TokenParser DoNotationElement-parseDoNotationElement = P.choice+parseDoNotationElement = withSourceSpan PositionedDoNotationElement $ P.choice [ parseDoNotationBind , parseDoNotationLet , DoNotationValue <$> parseValue@@ -515,55 +539,61 @@ -- | Parse a binder parseBinder :: TokenParser Binder parseBinder =- withSourceSpan- PositionedBinder- ( P.buildExpressionParser operators- . buildPostfixParser postfixTable- $ parseBinderAtom- )+ withSourceSpan+ PositionedBinder+ ( P.buildExpressionParser operators+ . buildPostfixParser postfixTable+ $ parseBinderAtom+ ) where- operators =- [ [ P.Infix (P.try (indented *> parseOpBinder P.<?> "binder operator") >>= \op ->- return (BinaryNoParensBinder op)) P.AssocRight+ operators =+ [ [ P.Infix (P.try (indented *> parseOpBinder P.<?> "binder operator") >>= \op ->+ return (BinaryNoParensBinder op)) P.AssocRight+ ] ]- ] - -- TODO: parsePolyType when adding support for polymorphic types- postfixTable = [ \b -> flip TypedBinder b <$> (indented *> doubleColon *> parseType)- ]+ postfixTable = [ \b -> flip TypedBinder b <$> (indented *> doubleColon *> parsePolyType) ] - parseOpBinder :: TokenParser Binder- parseOpBinder = OpBinder <$> parseQualified parseOperator+ parseOpBinder :: TokenParser Binder+ parseOpBinder = OpBinder <$> parseQualified parseOperator parseBinderAtom :: TokenParser Binder-parseBinderAtom = P.choice- [ parseNullBinder- , LiteralBinder <$> parseCharLiteral- , LiteralBinder <$> parseStringLiteral- , LiteralBinder <$> parseBooleanLiteral- , parseNumberLiteral- , parseVarOrNamedBinder- , parseConstructorBinder- , parseObjectBinder- , parseArrayBinder- , ParensInBinder <$> parens parseBinder- ] P.<?> "binder"+parseBinderAtom = withSourceSpan PositionedBinder+ (P.choice+ [ parseNullBinder+ , LiteralBinder <$> parseCharLiteral+ , LiteralBinder <$> parseStringLiteral+ , LiteralBinder <$> parseBooleanLiteral+ , parseNumberLiteral+ , parseVarOrNamedBinder+ , parseConstructorBinder+ , parseObjectBinder+ , parseArrayBinder+ , ParensInBinder <$> parens parseBinder+ ] P.<?> "binder") -- | Parse a binder as it would appear in a top level declaration parseBinderNoParens :: TokenParser Binder-parseBinderNoParens = P.choice- [ parseNullBinder- , LiteralBinder <$> parseCharLiteral- , LiteralBinder <$> parseStringLiteral- , LiteralBinder <$> parseBooleanLiteral- , parseNumberLiteral- , parseVarOrNamedBinder- , parseNullaryConstructorBinder- , parseObjectBinder- , parseArrayBinder- , ParensInBinder <$> parens parseBinder- ] P.<?> "binder"+parseBinderNoParens = withSourceSpan PositionedBinder+ (P.choice+ [ parseNullBinder+ , LiteralBinder <$> parseCharLiteral+ , LiteralBinder <$> parseStringLiteral+ , LiteralBinder <$> parseBooleanLiteral+ , parseNumberLiteral+ , parseVarOrNamedBinder+ , parseNullaryConstructorBinder+ , parseObjectBinder+ , parseArrayBinder+ , ParensInBinder <$> parens parseBinder+ ] P.<?> "binder") -- | Parse a guard-parseGuard :: TokenParser Guard-parseGuard = pipe *> indented *> parseValue+parseGuard :: TokenParser [Guard]+parseGuard =+ pipe *> indented *> P.sepBy1 (parsePatternGuard <|> parseConditionGuard) comma+ where+ parsePatternGuard =+ PatternGuard <$> P.try (parseBinder <* indented <* larrow) <*> parseValue+ parseConditionGuard =+ ConditionGuard <$> parseValue
src/Language/PureScript/Parser/Kinds.hs view
@@ -5,7 +5,6 @@ import Prelude.Compat -import Language.PureScript.Environment import Language.PureScript.Kinds import Language.PureScript.Parser.Common import Language.PureScript.Parser.Lexer@@ -14,21 +13,24 @@ import qualified Text.Parsec.Expr as P parseStar :: TokenParser Kind-parseStar = const kindType <$> symbol' "*"+parseStar = symbol' "*" *>+ P.parserFail "The `*` symbol is no longer used for the kind of types.\n The new equivalent is the named kind `Type`." parseBang :: TokenParser Kind-parseBang = const kindEffect <$> symbol' "!"+parseBang = symbol' "!" *>+ P.parserFail "The `!` symbol is no longer used for the kind of effects.\n The new equivalent is the named kind `Effect`, defined in `Control.Monad.Eff` in the `purescript-eff` library." parseNamedKind :: TokenParser Kind parseNamedKind = NamedKind <$> parseQualified kindName parseKindAtom :: TokenParser Kind-parseKindAtom = indented *> P.choice- [ parseStar- , parseBang- , parseNamedKind- , parens parseKind- ]+parseKindAtom =+ indented *> P.choice+ [ parseStar+ , parseBang+ , parseNamedKind+ , parens parseKind+ ] -- | -- Parse a kind
src/Language/PureScript/Parser/Lexer.hs view
@@ -6,6 +6,7 @@ , Token() , TokenParser() , lex+ , lexLenient , anyToken , token , match@@ -172,6 +173,14 @@ parseTokens :: Lexer u [PositionedToken] parseTokens = whitespace *> P.many parsePositionedToken <* P.skipMany parseComment <* P.eof++-- | Lexes the given file, and on encountering a parse error, returns the+-- progress made up to that point, instead of returning an error+lexLenient :: FilePath -> Text -> Either P.ParseError [PositionedToken]+lexLenient f s = updatePositions <$> P.parse parseTokensLenient f s++parseTokensLenient :: Lexer u [PositionedToken]+parseTokensLenient = whitespace *> P.many parsePositionedToken <* P.skipMany parseComment whitespace :: Lexer u () whitespace = P.skipMany (P.satisfy isSpace)
src/Language/PureScript/Parser/Types.hs view
@@ -9,6 +9,7 @@ import Control.Monad (when, unless) import Control.Applicative ((<|>))+import Data.Functor (($>)) import qualified Data.Text as T import Language.PureScript.AST.SourcePos@@ -68,13 +69,13 @@ , ParensInType <$> parens parsePolyType ] -parseConstrainedType :: TokenParser Type+parseConstrainedType :: TokenParser ([Constraint], Type) parseConstrainedType = do- constraints <- P.try (return <$> parseConstraint) <|> parens (commaSep1 parseConstraint)+ constraints <- parens (commaSep1 parseConstraint) <|> pure <$> parseConstraint _ <- rfatArrow indented ty <- parseType- return $ ConstrainedType constraints ty+ return (constraints, ty) where parseConstraint = do className <- parseQualified properName@@ -82,14 +83,34 @@ ty <- P.many parseTypeAtom return (Constraint className ty Nothing) +-- This is here to improve the error message when the user+-- tries to use the old style constraint contexts.+-- TODO: Remove this before 1.0+typeOrConstrainedType :: TokenParser Type+typeOrConstrainedType = do+ e <- P.try (Left <$> parseConstrainedType) <|> Right <$> parseTypeAtom+ case e of+ Left ([c], ty) -> pure (ConstrainedType c ty)+ Left _ ->+ P.unexpected $+ unlines [ "comma in constraints."+ , ""+ , "Class constraints in type annotations can no longer be grouped in parentheses."+ , "Each constraint should now be separated by `=>`, for example:"+ , " `(Applicative f, Semigroup a) => a -> f a -> f a`"+ , " would now be written as:"+ , " `Applicative f => Semigroup a => a -> f a -> f a`."+ ]+ Right ty -> pure ty+ parseAnyType :: TokenParser Type-parseAnyType = P.buildExpressionParser operators (buildPostfixParser postfixTable (P.try parseConstrainedType <|> parseTypeAtom)) P.<?> "type"+parseAnyType = P.buildExpressionParser operators (buildPostfixParser postfixTable typeOrConstrainedType) P.<?> "type" where operators = [ [ P.Infix (return TypeApp) P.AssocLeft ] , [ P.Infix (P.try (parseQualified parseOperator) >>= \ident -> return (BinaryNoParensType (TypeOp ident))) P.AssocRight ]- , [ P.Infix (rarrow *> return function) P.AssocRight ]+ , [ P.Infix (rarrow $> function) P.AssocRight ] ] postfixTable = [ \t -> KindedType t <$> (indented *> doubleColon *> parseKind) ]
src/Language/PureScript/Pretty.hs view
@@ -1,17 +1,12 @@--- |--- A collection of pretty printers for core data types:------ [@Language.PureScript.Pretty.Kinds@] Pretty printer for kinds------ [@Language.PureScript.Pretty.Values@] Pretty printer for values+-- | A collection of pretty printers for core data types: ----- [@Language.PureScript.Pretty.Types@] Pretty printer for types+-- * [@Language.PureScript.Pretty.Kinds@] Pretty printer for kinds ----- [@Language.PureScript.Pretty.JS@] Pretty printer for values, used for code generation+-- * [@Language.PureScript.Pretty.Values@] Pretty printer for values --+-- * [@Language.PureScript.Pretty.Types@] Pretty printer for types module Language.PureScript.Pretty (module P) where -import Language.PureScript.Pretty.JS as P import Language.PureScript.Pretty.Kinds as P import Language.PureScript.Pretty.Types as P import Language.PureScript.Pretty.Values as P
− src/Language/PureScript/Pretty/JS.hs
@@ -1,303 +0,0 @@--- |--- Pretty printer for the Javascript AST----module Language.PureScript.Pretty.JS- ( prettyPrintJS- , prettyPrintJSWithSourceMaps- ) where--import Prelude.Compat--import Control.Arrow ((<+>))-import Control.Monad (forM, mzero)-import Control.Monad.State (StateT, evalStateT)-import Control.PatternArrows-import qualified Control.Arrow as A--import Data.Maybe (fromMaybe)-import Data.Monoid ((<>))-import Data.Text (Text)-import qualified Data.Text as T--import Language.PureScript.AST (SourceSpan(..))-import Language.PureScript.CodeGen.JS.AST-import Language.PureScript.CodeGen.JS.Common-import Language.PureScript.Comments-import Language.PureScript.Crash-import Language.PureScript.Pretty.Common-import Language.PureScript.PSString (PSString, decodeString, prettyPrintStringJS)---- TODO (Christoph): Get rid of T.unpack / pack--literals :: (Emit gen) => Pattern PrinterState JS gen-literals = mkPattern' match'- where- match' :: (Emit gen) => JS -> StateT PrinterState Maybe gen- match' js = (addMapping' (getSourceSpan js) <>) <$> match js-- match :: (Emit gen) => JS -> StateT PrinterState Maybe gen- match (JSNumericLiteral _ n) = return $ emit $ T.pack $ either show show n- match (JSStringLiteral _ s) = return $ emit $ prettyPrintStringJS s- match (JSBooleanLiteral _ True) = return $ emit "true"- match (JSBooleanLiteral _ False) = return $ emit "false"- match (JSArrayLiteral _ xs) = mconcat <$> sequence- [ return $ emit "[ "- , intercalate (emit ", ") <$> forM xs prettyPrintJS'- , return $ emit " ]"- ]- match (JSObjectLiteral _ []) = return $ emit "{}"- match (JSObjectLiteral _ ps) = mconcat <$> sequence- [ return $ emit "{\n"- , withIndent $ do- jss <- forM ps $ \(key, value) -> fmap ((objectPropertyToString key <> emit ": ") <>) . prettyPrintJS' $ value- indentString <- currentIndent- return $ intercalate (emit ", \n") $ map (indentString <>) jss- , return $ emit "\n"- , currentIndent- , return $ emit "}"- ]- where- objectPropertyToString :: (Emit gen) => PSString -> gen- objectPropertyToString s =- emit $ case decodeString s of- Just s' | not (identNeedsEscaping s') ->- s'- _ ->- prettyPrintStringJS s- match (JSBlock _ sts) = mconcat <$> sequence- [ return $ emit "{\n"- , withIndent $ prettyStatements sts- , return $ emit "\n"- , currentIndent- , return $ emit "}"- ]- match (JSVar _ ident) = return $ emit ident- match (JSVariableIntroduction _ ident value) = mconcat <$> sequence- [ return $ emit $ "var " <> ident- , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintJS') value- ]- match (JSAssignment _ target value) = mconcat <$> sequence- [ prettyPrintJS' target- , return $ emit " = "- , prettyPrintJS' value- ]- match (JSWhile _ cond sts) = mconcat <$> sequence- [ return $ emit "while ("- , prettyPrintJS' cond- , return $ emit ") "- , prettyPrintJS' sts- ]- match (JSFor _ ident start end sts) = mconcat <$> sequence- [ return $ emit $ "for (var " <> ident <> " = "- , prettyPrintJS' start- , return $ emit $ "; " <> ident <> " < "- , prettyPrintJS' end- , return $ emit $ "; " <> ident <> "++) "- , prettyPrintJS' sts- ]- match (JSForIn _ ident obj sts) = mconcat <$> sequence- [ return $ emit $ "for (var " <> ident <> " in "- , prettyPrintJS' obj- , return $ emit ") "- , prettyPrintJS' sts- ]- match (JSIfElse _ cond thens elses) = mconcat <$> sequence- [ return $ emit "if ("- , prettyPrintJS' cond- , return $ emit ") "- , prettyPrintJS' thens- , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintJS') elses- ]- match (JSReturn _ value) = mconcat <$> sequence- [ return $ emit "return "- , prettyPrintJS' value- ]- match (JSThrow _ value) = mconcat <$> sequence- [ return $ emit "throw "- , prettyPrintJS' value- ]- match (JSBreak _ lbl) = return $ emit $ "break " <> lbl- match (JSContinue _ lbl) = return $ emit $ "continue " <> lbl- match (JSLabel _ lbl js) = mconcat <$> sequence- [ return $ emit $ lbl <> ": "- , prettyPrintJS' js- ]- match (JSComment _ com js) = mconcat <$> sequence- [ mconcat <$> forM com comment- , prettyPrintJS' js- ]- match (JSRaw _ js) = return $ emit js- match _ = mzero-- comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen- comment (LineComment com) = fmap mconcat $ sequence $- [ return $ emit "\n"- , currentIndent- , return $ emit "//" <> emit com <> emit "\n"- ]- comment (BlockComment com) = fmap mconcat $ sequence $- [ return $ emit "\n"- , currentIndent- , return $ emit "/**\n"- ] ++- map asLine (T.lines com) ++- [ currentIndent- , return $ emit " */\n"- , currentIndent- ]- where- asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen- asLine s = do- i <- currentIndent- return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"-- removeComments :: Text -> Text- removeComments t =- case T.stripPrefix "*/" t of- Just rest -> removeComments rest- Nothing -> case T.uncons t of- Just (x, xs) -> x `T.cons` removeComments xs- Nothing -> ""--conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)-conditional = mkPattern match- where- match (JSConditional ss cond th el) = Just ((ss, th, el), cond)- match _ = Nothing--accessor :: Pattern PrinterState JS (Text, JS)-accessor = mkPattern match- where- match (JSIndexer _ (JSStringLiteral _ prop) val) =- case decodeString prop of- Just s | not (identNeedsEscaping s) -> Just (s, val)- _ -> Nothing- match _ = Nothing--indexer :: (Emit gen) => Pattern PrinterState JS (gen, JS)-indexer = mkPattern' match- where- match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val- match _ = mzero--lam :: Pattern PrinterState JS ((Maybe Text, [Text], Maybe SourceSpan), JS)-lam = mkPattern match- where- match (JSFunction ss name args ret) = Just ((name, args, ss), ret)- match _ = Nothing--app :: (Emit gen) => Pattern PrinterState JS (gen, JS)-app = mkPattern' match- where- match (JSApp _ val args) = do- jss <- traverse prettyPrintJS' args- return (intercalate (emit ", ") jss, val)- match _ = mzero--typeOf :: Pattern PrinterState JS ((), JS)-typeOf = mkPattern match- where- match (JSTypeOf _ val) = Just ((), val)- match _ = Nothing--instanceOf :: Pattern PrinterState JS (JS, JS)-instanceOf = mkPattern match- where- match (JSInstanceOf _ val ty) = Just (val, ty)- match _ = Nothing--unary' :: (Emit gen) => UnaryOperator -> (JS -> Text) -> Operator PrinterState JS gen-unary' op mkStr = Wrap match (<>)- where- match :: (Emit gen) => Pattern PrinterState JS (gen, JS)- match = mkPattern match'- where- match' (JSUnary _ op' val) | op' == op = Just (emit $ mkStr val, val)- match' _ = Nothing--unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState JS gen-unary op str = unary' op (const str)--negateOperator :: (Emit gen) => Operator PrinterState JS gen-negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")- where- isNegate (JSUnary _ Negate _) = True- isNegate _ = False--binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState JS gen-binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)- where- match :: Pattern PrinterState JS (JS, JS)- match = mkPattern match'- where- match' (JSBinary _ op' v1 v2) | op' == op = Just (v1, v2)- match' _ = Nothing--prettyStatements :: (Emit gen) => [JS] -> StateT PrinterState Maybe gen-prettyStatements sts = do- jss <- forM sts prettyPrintJS'- indentString <- currentIndent- return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) jss---- |--- Generate a pretty-printed string representing a Javascript expression----prettyPrintJS1 :: (Emit gen) => JS -> gen-prettyPrintJS1 = fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'---- |--- Generate a pretty-printed string representing a collection of Javascript expressions at the same indentation level----prettyPrintJSWithSourceMaps :: [JS] -> (Text, [SMap])-prettyPrintJSWithSourceMaps js =- let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) js- in (s, mp)--prettyPrintJS :: [JS] -> Text-prettyPrintJS = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements--- |--- Generate an indented, pretty-printed string representing a Javascript expression----prettyPrintJS' :: (Emit gen) => JS -> StateT PrinterState Maybe gen-prettyPrintJS' = A.runKleisli $ runPattern matchValue- where- matchValue :: (Emit gen) => Pattern PrinterState JS gen- matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)- operators :: (Emit gen) => OperatorTable PrinterState JS gen- operators =- OperatorTable [ [ Wrap indexer $ \index val -> val <> emit "[" <> index <> emit "]" ]- , [ Wrap accessor $ \prop val -> val <> emit "." <> emit prop ]- , [ Wrap app $ \args val -> val <> emit "(" <> args <> emit ")" ]- , [ unary JSNew "new " ]- , [ Wrap lam $ \(name, args, ss) ret -> addMapping' ss <>- emit ("function "- <> fromMaybe "" name- <> "(" <> intercalate ", " args <> ") ")- <> ret ]- , [ Wrap typeOf $ \_ s -> emit "typeof " <> s ]- , [ unary Not "!"- , unary BitwiseNot "~"- , unary Positive "+"- , negateOperator ]- , [ binary Multiply "*"- , binary Divide "/"- , binary Modulus "%" ]- , [ binary Add "+"- , binary Subtract "-" ]- , [ binary ShiftLeft "<<"- , binary ShiftRight ">>"- , binary ZeroFillShiftRight ">>>" ]- , [ binary LessThan "<"- , binary LessThanOrEqualTo "<="- , binary GreaterThan ">"- , binary GreaterThanOrEqualTo ">="- , AssocR instanceOf $ \v1 v2 -> v1 <> emit " instanceof " <> v2 ]- , [ binary EqualTo "==="- , binary NotEqualTo "!==" ]- , [ binary BitwiseAnd "&" ]- , [ binary BitwiseXor "^" ]- , [ binary BitwiseOr "|" ]- , [ binary And "&&" ]- , [ binary Or "||" ]- , [ Wrap conditional $ \(ss, th, el) cond -> cond <> addMapping' ss <> emit " ? " <> prettyPrintJS1 th <> addMapping' ss <> emit " : " <> prettyPrintJS1 el ]- ]
src/Language/PureScript/Pretty/Types.hs view
@@ -37,10 +37,9 @@ -- TODO(Christoph): get rid of T.unpack s -constraintsAsBox :: TypeRenderOptions -> [Constraint] -> Box -> Box-constraintsAsBox tro constraints ty = case constraints of- [con] -> text "(" <> constraintAsBox con `before` (") " <> text doubleRightArrow <> " " <> ty)- xs -> vcat left (zipWith (\i con -> text (if i == 0 then "( " else ", ") <> constraintAsBox con) [0 :: Int ..] xs) `before` (") " <> text doubleRightArrow <> " " <> ty)+constraintsAsBox :: TypeRenderOptions -> Constraint -> Box -> Box+constraintsAsBox tro con ty =+ constraintAsBox con `before` (" " <> text doubleRightArrow <> " " <> ty) where doubleRightArrow = if troUnicode tro then "⇒" else "=>" @@ -105,7 +104,7 @@ go idents other = PrettyPrintForAll idents other convertForAlls other = other -constrained :: Pattern () Type ([Constraint], Type)+constrained :: Pattern () Type (Constraint, Type) constrained = mkPattern match where match (ConstrainedType deps ty) = Just (deps, ty)
src/Language/PureScript/Pretty/Values.hs view
@@ -66,8 +66,7 @@ printNode (key, Leaf val) = prettyPrintUpdateEntry d key val printNode (key, Branch val) = textT (prettyPrintObjectKey key) `beforeWithSpace` prettyPrintUpdate val prettyPrintValue d (App val arg) = prettyPrintValueAtom (d - 1) val `beforeWithSpace` prettyPrintValueAtom (d - 1) arg-prettyPrintValue d (Abs (Left arg) val) = text ('\\' : T.unpack (showIdent arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)-prettyPrintValue d (Abs (Right arg) val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)+prettyPrintValue d (Abs arg val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val) prettyPrintValue d (TypeClassDictionaryConstructorApp className ps) = text (T.unpack (runProperName (disqualify className)) ++ " ") <> prettyPrintValueAtom (d - 1) ps prettyPrintValue d (Case values binders) =@@ -125,12 +124,12 @@ prettyPrintDeclaration d _ | d < 0 = ellipsis prettyPrintDeclaration _ (TypeDeclaration ident ty) = text (T.unpack (showIdent ident) ++ " :: ") <> typeAsBox ty-prettyPrintDeclaration d (ValueDeclaration ident _ [] (Right val)) =+prettyPrintDeclaration d (ValueDeclaration ident _ [] [GuardedExpr [] val]) = text (T.unpack (showIdent ident) ++ " = ") <> prettyPrintValue (d - 1) val prettyPrintDeclaration d (BindingGroupDeclaration ds) = vsep 1 left (map (prettyPrintDeclaration (d - 1) . toDecl) ds) where- toDecl (nm, t, e) = ValueDeclaration nm t [] (Right e)+ toDecl (nm, t, e) = ValueDeclaration nm t [] [GuardedExpr [] e] prettyPrintDeclaration d (PositionedDeclaration _ _ decl) = prettyPrintDeclaration d decl prettyPrintDeclaration _ _ = internalError "Invalid argument to prettyPrintDeclaration" @@ -139,18 +138,19 @@ prettyPrintCaseAlternative d (CaseAlternative binders result) = text (T.unpack (T.unwords (map prettyPrintBinderAtom binders))) <> prettyPrintResult result where- prettyPrintResult :: Either [(Guard, Expr)] Expr -> Box- prettyPrintResult (Left gs) =+ prettyPrintResult :: [GuardedExpr] -> Box+ prettyPrintResult [GuardedExpr [] v] = text " -> " <> prettyPrintValue (d - 1) v+ prettyPrintResult gs = vcat left (map prettyPrintGuardedValue gs)- prettyPrintResult (Right v) = text " -> " <> prettyPrintValue (d - 1) v - prettyPrintGuardedValue :: (Guard, Expr) -> Box- prettyPrintGuardedValue (grd, val) = foldl1 before+ prettyPrintGuardedValue :: GuardedExpr -> Box+ prettyPrintGuardedValue (GuardedExpr [ConditionGuard grd] val) = foldl1 before [ text " | " , prettyPrintValue (d - 1) grd , text " -> " , prettyPrintValue (d - 1) val ]+ prettyPrintGuardedValue _ = internalError "There should only be ConditionGuards after desugaring cases" prettyPrintDoNotationElement :: Int -> DoNotationElement -> Box prettyPrintDoNotationElement d _ | d < 0 = ellipsis
src/Language/PureScript/Publish.hs view
@@ -15,7 +15,7 @@ , getGitWorkingTreeStatus , checkCleanWorkingTree , getVersionFromGitTag- , getBowerRepositoryInfo+ , getManifestRepositoryInfo , getModules , getResolvedDependencies ) where@@ -24,29 +24,25 @@ import Control.Arrow ((***)) import Control.Category ((>>>))-import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT) import Control.Monad.Writer.Strict (MonadWriter, WriterT, runWriterT, tell) -import Data.Aeson.BetterErrors (Parse, parse, keyMay, eachInObjectWithKey, eachInObject, key, keyOrDefault, asBool, asText)+import Data.Aeson.BetterErrors (Parse, parse, keyMay, eachInObjectWithKey, eachInObject, key, keyOrDefault, asBool, asString, asText)+import qualified Data.ByteString.Lazy as BL import Data.Char (isSpace) import Data.String (String, lines) import Data.List (stripPrefix, (\\), nubBy) import Data.List.NonEmpty (NonEmpty(..))-import Data.List.Split (splitOn) import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL import Data.Time.Clock (UTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import Data.Version import qualified Data.SPDX as SPDX -import System.Directory (doesFileExist, findExecutable)-import System.FilePath (pathSeparator)+import System.Directory (doesFileExist)+import System.FilePath.Glob (globDir1) import System.Process (readProcess)-import qualified System.FilePath.Glob as Glob-import qualified System.Info -import Web.Bower.PackageMeta (PackageMeta(..), BowerError(..), PackageName, runPackageName, parsePackageName, Repository(..))+import Web.Bower.PackageMeta (PackageMeta(..), PackageName, parsePackageName, Repository(..)) import qualified Web.Bower.PackageMeta as Bower import Language.PureScript.Publish.ErrorsWarnings@@ -72,14 +68,16 @@ -- | Attempt to retrieve package metadata from the current directory. -- Calls exitFailure if no package metadata could be retrieved.-unsafePreparePackage :: PublishOptions -> IO D.UploadedPackage-unsafePreparePackage opts = either (\e -> printError e >> exitFailure) pure =<< preparePackage opts+unsafePreparePackage :: FilePath -> FilePath -> PublishOptions -> IO D.UploadedPackage+unsafePreparePackage manifestFile resolutionsFile opts =+ either (\e -> printError e >> exitFailure) pure+ =<< preparePackage manifestFile resolutionsFile opts -- | Attempt to retrieve package metadata from the current directory. -- Returns a PackageError on failure-preparePackage :: PublishOptions -> IO (Either PackageError D.UploadedPackage)-preparePackage opts =- runPrepareM (preparePackage' opts)+preparePackage :: FilePath -> FilePath -> PublishOptions -> IO (Either PackageError D.UploadedPackage)+preparePackage manifestFile resolutionsFile opts =+ runPrepareM (preparePackage' manifestFile resolutionsFile opts) >>= either (pure . Left) (fmap Right . handleWarnings) where@@ -119,32 +117,36 @@ catchLeft :: Applicative f => Either a b -> (a -> f b) -> f b catchLeft a f = either f pure a -preparePackage' :: PublishOptions -> PrepareM D.UploadedPackage-preparePackage' opts = do- unlessM (liftIO (doesFileExist "bower.json")) (userError BowerJSONNotFound)+preparePackage' :: FilePath -> FilePath -> PublishOptions -> PrepareM D.UploadedPackage+preparePackage' manifestFile resolutionsFile opts = do+ unlessM (liftIO (doesFileExist manifestFile)) (userError PackageManifestNotFound) checkCleanWorkingTree opts - pkgMeta <- liftIO (Bower.decodeFile "bower.json")- >>= flip catchLeft (userError . CouldntDecodeBowerJSON)+ pkgMeta <- liftIO (Bower.decodeFile manifestFile)+ >>= flip catchLeft (userError . CouldntDecodePackageManifest) checkLicense pkgMeta (pkgVersionTag, pkgVersion) <- publishGetVersion opts pkgTagTime <- Just <$> publishGetTagTime opts pkgVersionTag- pkgGithub <- getBowerRepositoryInfo pkgMeta- (pkgModules, pkgModuleMap) <- getModules+ pkgGithub <- getManifestRepositoryInfo pkgMeta let declaredDeps = map fst (bowerDependencies pkgMeta ++ bowerDevDependencies pkgMeta)- pkgResolvedDependencies <- getResolvedDependencies declaredDeps+ resolvedDeps <- getResolvedDependencies resolutionsFile declaredDeps + (pkgModules, pkgModuleMap) <- getModules (map (second fst) resolvedDeps)+ let pkgUploader = D.NotYetKnown let pkgCompilerVersion = P.version+ let pkgResolvedDependencies = map (second snd) resolvedDeps return D.Package{..} -getModules :: PrepareM ([D.Module], Map P.ModuleName PackageName)-getModules = do- (inputFiles, depsFiles) <- liftIO getInputAndDepsFiles+getModules+ :: [(PackageName, FilePath)]+ -> PrepareM ([D.Module], Map P.ModuleName PackageName)+getModules paths = do+ (inputFiles, depsFiles) <- liftIO (getInputAndDepsFiles paths) (modules', moduleMap) <- parseFilesInPackages inputFiles depsFiles case runExcept (D.convertModulesInPackage modules' moduleMap) of@@ -194,13 +196,13 @@ -- | Given a git tag, get the time it was created. getTagTime :: Text -> PrepareM UTCTime getTagTime tag = do- out <- readProcess' "git" ["show", T.unpack tag, "--no-patch", "--format=%aI"] ""- case mapMaybe D.parseTime (lines out) of- [t] -> pure t+ out <- readProcess' "git" ["log", "-1", "--format=%ct", T.unpack tag] ""+ case mapMaybe readMaybe (lines out) of+ [t] -> pure . posixSecondsToUTCTime . fromInteger $ t _ -> internalError (CouldntParseGitTagDate tag) -getBowerRepositoryInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)-getBowerRepositoryInfo = either (userError . BadRepositoryField) return . tryExtract+getManifestRepositoryInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)+getManifestRepositoryInfo = either (userError . BadRepositoryField) return . tryExtract where tryExtract pkgMeta = case bowerRepository pkgMeta of@@ -258,12 +260,9 @@ data DependencyStatus = Missing- -- ^ Listed in bower.json, but not installed.+ -- ^ Listed in package manifest, but not installed. | NoResolution- -- ^ In the output of `bower list --json --offline`, there was no- -- _resolution key. This can be caused by adding the dependency using- -- `bower link`, or simply copying it into bower_components instead of- -- installing it normally.+ -- ^ In the resolutions file, there was no _resolution key. | ResolvedOther Text -- ^ Resolved, but to something other than a version. The Text argument -- is the resolution type. The values it can take that I'm aware of are@@ -273,10 +272,10 @@ -- "v0.1.0"). deriving (Show, Eq) --- Go through all bower dependencies which contain purescript code, and+-- Go through all dependencies which contain purescript code, and -- extract their versions. ----- In the case where a bower dependency is taken from a particular version,+-- In the case where a dependency is taken from a particular version, -- that's easy; take that version. In any other case (eg, a branch, or a commit -- sha) we print a warning that documentation links will not work, and avoid -- linking to documentation for any types from that package.@@ -286,10 +285,10 @@ -- probably for a reason. However, docs are only ever available for released -- versions. Therefore there will probably be no version of the docs which is -- appropriate to link to, and we should omit links.-getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]-getResolvedDependencies declaredDeps = do- bower <- findBowerExecutable- depsBS <- packUtf8 <$> readProcess' bower ["list", "--json", "--offline"] ""+getResolvedDependencies :: FilePath -> [PackageName] -> PrepareM [(PackageName, (FilePath, Version))]+getResolvedDependencies resolutionsFile declaredDeps = do+ unlessM (liftIO (doesFileExist resolutionsFile)) (userError ResolutionsFileNotFound)+ depsBS <- liftIO (BL.readFile resolutionsFile) -- Check for undeclared dependencies toplevels <- catchJSON (parse asToplevelDependencies depsBS)@@ -299,111 +298,93 @@ handleDeps deps where- packUtf8 = TL.encodeUtf8 . TL.pack- catchJSON = flip catchLeft (internalError . JSONError FromBowerList)--findBowerExecutable :: PrepareM String-findBowerExecutable = do- mname <- liftIO . runMaybeT . msum . map (MaybeT . findExecutable) $ names- maybe (userError (BowerExecutableNotFound names)) return mname- where- names = case System.Info.os of- "mingw32" -> ["bower", "bower.cmd"]- _ -> ["bower"]+ catchJSON = flip catchLeft (internalError . JSONError FromResolutions) --- | Extracts all dependencies and their versions from--- `bower list --json --offline`-asResolvedDependencies :: Parse BowerError [(PackageName, DependencyStatus)]+-- | Extracts all dependencies and their versions from a "resolutions" file, which+-- is based on the output of `bower list --json --offline`+asResolvedDependencies :: Parse D.ManifestError [(PackageName, (Maybe FilePath, DependencyStatus))] asResolvedDependencies = nubBy ((==) `on` fst) <$> go where go = fmap (fromMaybe []) $ keyMay "dependencies" $- (++) <$> eachInObjectWithKey parsePackageName asDependencyStatus+ (++) <$> eachInObjectWithKey parsePackageName asDirectoryAndDependencyStatus <*> (concatMap snd <$> eachInObject asResolvedDependencies) --- | Extracts only the top level dependency names from the output of--- `bower list --json --offline`-asToplevelDependencies :: Parse BowerError [PackageName]+-- | Extracts only the top level dependency names from a resolutions file.+asToplevelDependencies :: Parse D.ManifestError [PackageName] asToplevelDependencies = fmap (map fst) $ key "dependencies" $ eachInObjectWithKey parsePackageName (return ()) -asDependencyStatus :: Parse e DependencyStatus-asDependencyStatus = do+asDirectoryAndDependencyStatus :: Parse e (Maybe FilePath, DependencyStatus)+asDirectoryAndDependencyStatus = do isMissing <- keyOrDefault "missing" False asBool if isMissing then- return Missing- else- key "pkgMeta" $+ return (Nothing, Missing)+ else do+ directory <- key "canonicalDir" asString+ status <- key "pkgMeta" $ keyOrDefault "_resolution" NoResolution $ do type_ <- key "type" asText case type_ of "version" -> ResolvedVersion <$> key "tag" asText other -> return (ResolvedOther other)+ return (Just directory, status) warnUndeclared :: [PackageName] -> [PackageName] -> PrepareM () warnUndeclared declared actual = traverse_ (warn . UndeclaredDependency) (actual \\ declared) -handleDeps ::- [(PackageName, DependencyStatus)] -> PrepareM [(PackageName, Version)]+handleDeps+ :: [(PackageName, (Maybe FilePath, DependencyStatus))]+ -> PrepareM [(PackageName, (FilePath, Version))] handleDeps deps = do- let (missing, noVersion, installed) = partitionDeps deps+ let (missing, noVersion, installed, missingPath) = partitionDeps deps case missing of (x:xs) -> userError (MissingDependencies (x :| xs)) [] -> do traverse_ (warn . NoResolvedVersion) noVersion- withVersions <- catMaybes <$> traverse tryExtractVersion' installed- filterM (liftIO . isPureScript . bowerDir . fst) withVersions+ traverse_ (warn . MissingPath) missingPath+ catMaybes <$> traverse tryExtractVersion' installed where- partitionDeps = foldr go ([], [], [])- go (pkgName, d) (ms, os, is) =+ partitionDeps = foldr go ([], [], [], [])+ go (pkgName, (Nothing, _)) (ms, os, is, mp) =+ (ms, os, is, pkgName : mp)+ go (pkgName, (Just path, d)) (ms, os, is, mp) = case d of- Missing -> (pkgName : ms, os, is)- NoResolution -> (ms, pkgName : os, is)- ResolvedOther _ -> (ms, pkgName : os, is)- ResolvedVersion v -> (ms, os, (pkgName, v) : is)-- bowerDir pkgName = T.unpack $ "bower_components/" <> runPackageName pkgName+ Missing -> (pkgName : ms, os, is, mp)+ NoResolution -> (ms, pkgName : os, is, mp)+ ResolvedOther _ -> (ms, pkgName : os, is, mp)+ ResolvedVersion v -> (ms, os, (pkgName, (path, v)) : is, mp) -- Try to extract a version, and warn if unsuccessful.- tryExtractVersion' :: (PackageName, Text) -> PrepareM (Maybe (PackageName, Version))+ tryExtractVersion'+ :: (PackageName, (extra, Text))+ -> PrepareM (Maybe (PackageName, (extra, Version))) tryExtractVersion' pair =- maybe (warn (UnacceptableVersion pair) >> return Nothing)+ maybe (warn (UnacceptableVersion (fmap snd pair)) >> return Nothing) (return . Just) (tryExtractVersion pair) -tryExtractVersion :: (PackageName, Text) -> Maybe (PackageName, Version)-tryExtractVersion (pkgName, tag) =+tryExtractVersion+ :: (PackageName, (extra, Text))+ -> Maybe (PackageName, (extra, Version))+tryExtractVersion (pkgName, (extra, tag)) = let tag' = fromMaybe tag (T.stripPrefix "v" tag)- in (pkgName,) <$> D.parseVersion' (T.unpack tag')---- | Returns whether it looks like there is a purescript package checked out--- in the given directory.-isPureScript :: FilePath -> IO Bool-isPureScript dir = do- files <- Glob.globDir1 purescriptSourceFiles dir- return (not (null files))+ in (pkgName,) . (extra,) <$> D.parseVersion' (T.unpack tag') -getInputAndDepsFiles :: IO ([FilePath], [(PackageName, FilePath)])-getInputAndDepsFiles = do+getInputAndDepsFiles+ :: [(PackageName, FilePath)]+ -> IO ([FilePath], [(PackageName, FilePath)])+getInputAndDepsFiles depPaths = do inputFiles <- globRelative purescriptSourceFiles- depsFiles' <- globRelative purescriptDepsFiles- return (inputFiles, mapMaybe withPackageName depsFiles')--withPackageName :: FilePath -> Maybe (PackageName, FilePath)-withPackageName fp = (,fp) <$> getPackageName fp--getPackageName :: FilePath -> Maybe PackageName-getPackageName fp = do- let xs = splitOn [pathSeparator] fp- ys <- stripPrefix ["bower_components"] xs- y <- headMay ys- case Bower.mkPackageName (T.pack y) of- Right name -> Just name- Left _ -> Nothing+ let handleDep (pkgName, path) = do+ depFiles <- globDir1 purescriptSourceFiles path+ return (map (pkgName,) depFiles)+ depFiles <- concat <$> traverse handleDep depPaths+ return (inputFiles, depFiles)
src/Language/PureScript/Publish/ErrorsWarnings.hs view
@@ -18,7 +18,7 @@ import Control.Exception (IOException) import Data.Aeson.BetterErrors (ParseError, displayError)-import Data.List (intersperse, intercalate)+import Data.List (intersperse) import Data.List.NonEmpty (NonEmpty(..)) import Data.Maybe import Data.Monoid@@ -27,10 +27,11 @@ import Data.Text (Text) import qualified Data.Text as T +import Language.PureScript.Docs.Types (ManifestError) import Language.PureScript.Publish.BoxesHelpers import qualified Language.PureScript as P -import Web.Bower.PackageMeta (BowerError, PackageName, runPackageName, showBowerError)+import Web.Bower.PackageMeta (PackageName, runPackageName, showBowerError) import qualified Web.Bower.PackageMeta as Bower -- | An error which meant that it was not possible to retrieve metadata for a@@ -46,13 +47,14 @@ | UndeclaredDependency PackageName | UnacceptableVersion (PackageName, Text) | DirtyWorkingTree_Warn+ | MissingPath PackageName deriving (Show) -- | An error that should be fixed by the user. data UserError- = BowerJSONNotFound- | BowerExecutableNotFound [String] -- list of executable names tried- | CouldntDecodeBowerJSON (ParseError BowerError)+ = PackageManifestNotFound+ | ResolutionsFileNotFound+ | CouldntDecodePackageManifest (ParseError ManifestError) | TagMustBeCheckedOut | AmbiguousVersions [Version] -- Invariant: should contain at least two elements | BadRepositoryField RepositoryFieldError@@ -72,13 +74,13 @@ -- | An error that probably indicates a bug in this module. data InternalError- = JSONError JSONSource (ParseError BowerError)+ = JSONError JSONSource (ParseError ManifestError) | CouldntParseGitTagDate Text deriving (Show) data JSONSource = FromFile FilePath- | FromBowerList+ | FromResolutions deriving (Show) data OtherError@@ -121,24 +123,19 @@ displayUserError :: UserError -> Box displayUserError e = case e of- BowerJSONNotFound ->+ PackageManifestNotFound -> para (- "The bower.json file was not found. Please create one, or run " +++ "The package manifest file was not found. Please create one, or run " ++ "`pulp init`." )- BowerExecutableNotFound names ->- para (concat- [ "The Bower executable was not found (tried: ", format names, "). Please"- , " ensure that bower is installed and on your PATH."- ])- where- format = intercalate ", " . map show- CouldntDecodeBowerJSON err ->+ ResolutionsFileNotFound ->+ para "The resolutions file was not found."+ CouldntDecodePackageManifest err -> vcat- [ para "There was a problem with your bower.json file:"+ [ para "There was a problem with your package manifest file:" , indented (vcat (map (para . T.unpack) (displayError showBowerError err))) , spacer- , para "Please ensure that your bower.json file is valid."+ , para "Please ensure that your package manifest file is valid." ] TagMustBeCheckedOut -> vcat@@ -174,7 +171,7 @@ NoLicenseSpecified -> vcat $ [ para (concat- [ "No license is specified in bower.json. Please add one, using the "+ [ "No license is specified in package manifest. Please add one, using the " , "SPDX license expression format. For example, any of the " , "following would be acceptable:" ])@@ -195,7 +192,7 @@ InvalidLicense -> vcat $ [ para (concat- [ "The license specified in bower.json is not a valid SPDX license "+ [ "The license specified in package manifest is not a valid SPDX license " , "expression. Please use the SPDX license expression format. For " , "example, any of the following would be acceptable:" ])@@ -207,20 +204,13 @@ pl a b = if singular then b else a do_ = pl "do" "does" dependencies = pl "dependencies" "dependency"- them = pl "them" "it" in vcat $ [ para (concat- [ "The following Bower ", dependencies, " ", do_, " not appear to be "+ [ "The following ", dependencies, " ", do_, " not appear to be " , "installed:" ]) ] ++ bulletedListT runPackageName (NonEmpty.toList pkgs)- ++- [ spacer- , para (concat- [ "Please install ", them, " first, by running `bower install`."- ])- ] CompileError err -> vcat [ para "Compile error:"@@ -247,7 +237,7 @@ RepositoryFieldMissing -> vcat [ para (concat- [ "The 'repository' field is not present in your bower.json file. "+ [ "The 'repository' field is not present in your package manifest file. " , "Without this information, Pursuit would not be able to generate " , "source links in your package's documentation. Please add one - like " , "this, for example:"@@ -263,21 +253,21 @@ ] BadRepositoryType ty -> para (concat- [ "In your bower.json file, the repository type is currently listed as "+ [ "In your package manifest file, the repository type is currently listed as " , "\"" ++ T.unpack ty ++ "\". Currently, only git repositories are supported. " , "Please publish your code in a git repository, and then update the "- , "repository type in your bower.json file to \"git\"."+ , "repository type in your package manifest file to \"git\"." ]) NotOnGithub -> vcat [ para (concat- [ "The repository url in your bower.json file does not point to a "+ [ "The repository url in your package manifest file does not point to a " , "GitHub repository. Currently, Pursuit does not support packages " , "which are not hosted on GitHub." ]) , spacer , para (concat- [ "Please update your bower.json file to point to a GitHub repository. "+ [ "Please update your package manifest file to point to a GitHub repository. " , "Alternatively, if you would prefer not to host your package on " , "GitHub, please open an issue:" ])@@ -298,8 +288,8 @@ displayJSONSource s = case s of FromFile fp -> "in file " ++ show fp- FromBowerList ->- "in the output of `bower list --json --offline`"+ FromResolutions ->+ "in resolutions file" displayOtherError :: OtherError -> Box displayOtherError e = case e of@@ -317,23 +307,25 @@ , undeclaredDependencies :: [PackageName] , unacceptableVersions :: [(PackageName, Text)] , dirtyWorkingTree :: Any+ , missingPaths :: [PackageName] } deriving (Show, Eq, Ord) instance Monoid CollectedWarnings where- mempty = CollectedWarnings mempty mempty mempty mempty- mappend (CollectedWarnings as bs cs d)- (CollectedWarnings as' bs' cs' d') =- CollectedWarnings (as <> as') (bs <> bs') (cs <> cs') (d <> d')+ mempty = CollectedWarnings mempty mempty mempty mempty mempty+ mappend (CollectedWarnings as bs cs d es)+ (CollectedWarnings as' bs' cs' d' es') =+ CollectedWarnings (as <> as') (bs <> bs') (cs <> cs') (d <> d') (es <> es') collectWarnings :: [PackageWarning] -> CollectedWarnings collectWarnings = foldMap singular where singular w = case w of- NoResolvedVersion pn -> CollectedWarnings [pn] mempty mempty mempty- UndeclaredDependency pn -> CollectedWarnings mempty [pn] mempty mempty- UnacceptableVersion t -> CollectedWarnings mempty mempty [t] mempty- DirtyWorkingTree_Warn -> CollectedWarnings mempty mempty mempty (Any True)+ NoResolvedVersion pn -> CollectedWarnings [pn] mempty mempty mempty mempty+ UndeclaredDependency pn -> CollectedWarnings mempty [pn] mempty mempty mempty+ UnacceptableVersion t -> CollectedWarnings mempty mempty [t] mempty mempty+ DirtyWorkingTree_Warn -> CollectedWarnings mempty mempty mempty (Any True) mempty+ MissingPath pn -> CollectedWarnings mempty mempty mempty mempty [pn] renderWarnings :: [PackageWarning] -> Box renderWarnings warns =@@ -345,6 +337,7 @@ , if getAny dirtyWorkingTree then Just warnDirtyWorkingTree else Nothing+ , go warnMissingPaths missingPaths ] in case catMaybes mboxes of [] -> nullBox@@ -370,9 +363,8 @@ [ spacer , para (concat ["Links to types in ", anyOfThese, " ", packages, " will not work. In "- , "order to make links work, edit your bower.json to specify a version"- , " or a version range for ", these, " ", packages, ", and rerun "- , "`bower install`."+ , "order to make links work, edit your package manifest to specify a version"+ , " or a version range for ", these, " ", packages, "." ]) ] @@ -386,8 +378,8 @@ dependencies = pl "dependencies" "a dependency" in vcat $ para (concat- [ "The following Bower ", packages, " ", are, " installed, but not "- , "declared as ", dependencies, " in your bower.json file:"+ [ "The following ", packages, " ", are, " installed, but not "+ , "declared as ", dependencies, " in your package manifest file:" ]) : bulletedListT runPackageName (NonEmpty.toList pkgNames) @@ -403,7 +395,7 @@ versions = pl "versions" "version" in vcat $ [ para (concat- [ "The following installed Bower ", packages', " ", versions, " could "+ [ "The following installed ", packages', " ", versions, " could " , "not be parsed:" ]) ] ++@@ -412,9 +404,8 @@ [ spacer , para (concat ["Links to types in ", anyOfThese, " ", packages, " will not work. In "- , "order to make links work, edit your bower.json to specify an "- , "acceptable version or version range for ", these, " ", packages, ", "- , "and rerun `bower install`."+ , "order to make links work, edit your package manifest to specify an "+ , "acceptable version or version range for ", these, " ", packages, "." ]) ] where@@ -426,6 +417,19 @@ "Your working tree is dirty. (Note: this would be an error if it " ++ "were not a dry run)" )++warnMissingPaths :: NonEmpty PackageName -> Box+warnMissingPaths pkgs =+ let singular = NonEmpty.length pkgs == 1+ pl a b = if singular then b else a++ packages = pl "packages" "package"+ in vcat $+ para (concat+ [ "The following installed ", packages, " were "+ , "missing path information in the resolutions file:"+ ])+ : bulletedListT runPackageName (NonEmpty.toList pkgs) printWarnings :: [PackageWarning] -> IO () printWarnings = printToStderr . renderWarnings
src/Language/PureScript/Publish/Utils.hs view
@@ -1,41 +1,14 @@- -module Language.PureScript.Publish.Utils where - -import Prelude.Compat +module Language.PureScript.Publish.Utils where -import Data.Either (partitionEithers) -import Data.List +import Prelude.Compat -import System.Directory -import System.Exit (exitFailure) -import System.FilePath (pathSeparator) -import System.IO (hPutStrLn, stderr) -import qualified System.FilePath.Glob as Glob +import System.Directory+import System.FilePath.Glob (Pattern, compile, globDir1) -- | Glob relative to the current directory, and produce relative pathnames. -globRelative :: Glob.Pattern -> IO [FilePath] -globRelative pat = do - currentDir <- getCurrentDirectory - filesAbsolute <- Glob.globDir1 pat currentDir - let prefix = currentDir ++ [pathSeparator] - let (fails, paths) = partitionEithers . map (stripPrefix' prefix) $ filesAbsolute - if null fails - then return paths - else do - let p = hPutStrLn stderr - p "Internal error in Language.PureScript.Publish.Utils.globRelative" - p "Unmatched files:" - mapM_ p fails - exitFailure - - where - stripPrefix' prefix dir = - maybe (Left dir) Right $ stripPrefix prefix dir +globRelative :: Pattern -> IO [FilePath]+globRelative pat = getCurrentDirectory >>= globDir1 pat -- | Glob pattern for PureScript source files. -purescriptSourceFiles :: Glob.Pattern -purescriptSourceFiles = Glob.compile "src/**/*.purs" - --- | Glob pattern for PureScript dependency files. -purescriptDepsFiles :: Glob.Pattern -purescriptDepsFiles = Glob.compile "bower_components/*/src/**/*.purs" +purescriptSourceFiles :: Pattern+purescriptSourceFiles = compile "src/**/*.purs"
src/Language/PureScript/Sugar.hs view
@@ -18,6 +18,7 @@ import Language.PureScript.Sugar.BindingGroups as S import Language.PureScript.Sugar.CaseDeclarations as S import Language.PureScript.Sugar.DoNotation as S+import Language.PureScript.Sugar.LetPattern as S import Language.PureScript.Sugar.Names as S import Language.PureScript.Sugar.ObjectWildcards as S import Language.PureScript.Sugar.Operators as S@@ -57,7 +58,8 @@ map desugarSignedLiterals >>> traverse desugarObjectConstructors >=> traverse desugarDoModule- >=> traverse desugarCasesModule+ >=> map desugarLetPatternModule+ >>> traverse desugarCasesModule >=> traverse desugarTypeDeclarationsModule >=> desugarImports externs >=> rebracket externs@@ -65,3 +67,4 @@ >=> traverse (deriveInstances externs) >=> desugarTypeClasses externs >=> traverse createBindingGroupsModule+
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -10,13 +10,14 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad ((<=<)) import Control.Monad.Error.Class (MonadError(..)) import Data.Graph-import Data.List (nub, intersect)-import Data.Maybe (isJust, mapMaybe)+import Data.List (intersect)+import Data.Maybe (isJust) import qualified Data.Set as S import Language.PureScript.AST@@ -92,7 +93,8 @@ where go (DataBindingGroupDeclaration ds) = ds go (BindingGroupDeclaration ds) =- map (\(ident, nameKind, val) -> ValueDeclaration ident nameKind [] (Right val)) ds+ map (\(ident, nameKind, val) ->+ ValueDeclaration ident nameKind [] [MkUnguarded val]) ds go (PositionedDeclaration pos com d) = map (PositionedDeclaration pos com) $ go d go other = [other]@@ -102,11 +104,11 @@ collapseBindingGroupsForValue other = other usedIdents :: ModuleName -> Declaration -> [Ident]-usedIdents moduleName = nub . usedIdents' S.empty . getValue+usedIdents moduleName = ordNub . usedIdents' S.empty . getValue where def _ _ = [] - getValue (ValueDeclaration _ _ [] (Right val)) = val+ getValue (ValueDeclaration _ _ [] [MkUnguarded val]) = val getValue ValueDeclaration{} = internalError "Binders should have been desugared" getValue (PositionedDeclaration _ _ d) = getValue d getValue _ = internalError "Expected ValueDeclaration"@@ -123,7 +125,7 @@ usedImmediateIdents :: ModuleName -> Declaration -> [Ident] usedImmediateIdents moduleName = let (f, _, _, _, _) = everythingWithContextOnValues True [] (++) def usedNamesE def def def- in nub . f+ in ordNub . f where def s _ = (s, []) @@ -137,14 +139,14 @@ usedTypeNames :: ModuleName -> Declaration -> [ProperName 'TypeName] usedTypeNames moduleName = let (f, _, _, _, _) = accumTypes (everythingOnTypes (++) usedNames)- in nub . f+ in ordNub . f where usedNames :: Type -> [ProperName 'TypeName]- usedNames (ConstrainedType constraints _) =- flip mapMaybe constraints $ \case+ usedNames (ConstrainedType con _) =+ case con of (Constraint (Qualified (Just moduleName') name) _ _)- | moduleName == moduleName' -> Just (coerceProperName name)- _ -> Nothing+ | moduleName == moduleName' -> [coerceProperName name]+ _ -> [] usedNames (TypeConstructor (Qualified (Just moduleName') name)) | moduleName == moduleName' = [name] usedNames _ = []@@ -195,7 +197,7 @@ cycleError :: Declaration -> MultipleErrors cycleError (PositionedDeclaration p _ d) = onErrorMessages (withPosition p) $ cycleError d- cycleError (ValueDeclaration n _ _ (Right _)) = errorMessage $ CycleInDeclaration n+ cycleError (ValueDeclaration n _ _ [MkUnguarded _]) = errorMessage $ CycleInDeclaration n cycleError _ = internalError "cycleError: Expected ValueDeclaration" toDataBindingGroup@@ -216,7 +218,7 @@ isTypeSynonym _ = Nothing fromValueDecl :: Declaration -> (Ident, NameKind, Expr)-fromValueDecl (ValueDeclaration ident nameKind [] (Right val)) = (ident, nameKind, val)+fromValueDecl (ValueDeclaration ident nameKind [] [MkUnguarded val]) = (ident, nameKind, val) fromValueDecl ValueDeclaration{} = internalError "Binders should have been desugared" fromValueDecl (PositionedDeclaration _ _ d) = fromValueDecl d fromValueDecl _ = internalError "Expected ValueDeclaration"
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -8,12 +8,12 @@ ) where import Prelude.Compat+import Protolude (ordNub) -import Data.Either (isLeft)-import Data.List (nub, groupBy, foldl1')+import Data.List (groupBy, foldl1') import Data.Maybe (catMaybes, mapMaybe) -import Control.Monad ((<=<), replicateM, join, unless)+import Control.Monad ((<=<), forM, replicateM, join, unless) import Control.Monad.Error.Class (MonadError(..)) import Control.Monad.Supply.Class @@ -22,7 +22,6 @@ import Language.PureScript.Environment import Language.PureScript.Errors import Language.PureScript.Names-import Language.PureScript.Traversals import Language.PureScript.TypeChecker.Monad (guardWith) -- |@@ -39,6 +38,222 @@ <*> pure exps -- |+-- Desugar case with pattern guards and pattern clauses to a+-- series of nested case expressions.+--+desugarCase :: forall m. (MonadSupply m)+ => Expr+ -> m Expr+desugarCase (Case scrut alternatives)+ | any (not . isTrivialExpr) scrut = do+ -- in case the scrutinee is non trivial (e.g. not a Var or Literal)+ -- we may evaluate the scrutinee more than once when a guard occurrs.+ -- We bind the scrutinee to Vars here to mitigate this case.+ (scrut', scrut_decls) <- unzip <$> forM scrut (\e -> do+ scrut_id <- freshIdent'+ pure ( Var (Qualified Nothing scrut_id)+ , ValueDeclaration scrut_id Private [] [MkUnguarded e]+ )+ )+ Let scrut_decls <$> desugarCase (Case scrut' alternatives)+ where+ isTrivialExpr (Var _) = True+ isTrivialExpr (Literal _) = True+ isTrivialExpr (Accessor _ e) = isTrivialExpr e+ isTrivialExpr (Parens e) = isTrivialExpr e+ isTrivialExpr (PositionedValue _ _ e) = isTrivialExpr e+ isTrivialExpr _ = False++desugarCase (Case scrut alternatives) =+ let+ -- Alternatives which do not have guards are+ -- left as-is. Alternatives which+ --+ -- 1) have multiple clauses of the form+ -- binder | g_1+ -- , g_2+ -- , ...+ -- , g_n+ -- -> expr+ --+ -- 2) and/or contain pattern guards of the form+ -- binder | pat_bind <- e+ -- , ...+ --+ -- are desugared to a sequence of nested case expressions.+ --+ -- Consider an example case expression:+ --+ -- case e of+ -- (T s) | Just info <- Map.lookup s names+ -- , is_used info+ -- -> f info+ --+ -- We desugar this to+ --+ -- case e of+ -- (T s) -> case Map.lookup s names of+ -- Just info -> case is_used info of+ -- True -> f info+ -- (_ -> <partial>)+ -- (_ -> <partial>)+ --+ -- Note that if the original case is partial the desugared+ -- case is also partial.+ --+ -- Consider an exhaustive case expression:+ --+ -- case e of+ -- (T s) | Just info <- Map.lookup s names+ -- , is_used info+ -- -> f info+ -- _ -> Nothing+ --+ -- desugars to:+ --+ -- case e of+ -- _ -> let+ -- v _ = Nothing+ -- in+ -- case e of+ -- (T s) -> case Map.lookup s names of+ -- Just info -> f info+ -- _ -> v true+ -- _ -> v true+ --+ -- This might look strange but simplifies the algorithm a lot.+ --+ desugarAlternatives :: [CaseAlternative]+ -> m [CaseAlternative]+ desugarAlternatives [] = pure []++ -- the trivial case: no guards+ desugarAlternatives (a@(CaseAlternative _ [MkUnguarded _]) : as) =+ (a :) <$> desugarAlternatives as++ -- Special case: CoreFn understands single condition guards on+ -- binders right hand side.+ desugarAlternatives (CaseAlternative ab ge : as)+ | not (null cond_guards) =+ (CaseAlternative ab cond_guards :)+ <$> desugarGuardedAlternative ab rest as+ | otherwise = desugarGuardedAlternative ab ge as+ where+ (cond_guards, rest) = span isSingleCondGuard ge++ isSingleCondGuard (GuardedExpr [ConditionGuard _] _) = True+ isSingleCondGuard _ = False++ desugarGuardedAlternative :: [Binder]+ -> [GuardedExpr]+ -> [CaseAlternative]+ -> m [CaseAlternative]+ desugarGuardedAlternative _vb [] rem_alts =+ desugarAlternatives rem_alts++ desugarGuardedAlternative vb (GuardedExpr gs e : ge) rem_alts = do+ rhs <- desugarAltOutOfLine vb ge rem_alts $ \alt_fail ->+ let+ -- if the binder is a var binder we must not add+ -- the fail case as it results in unreachable+ -- alternative+ alt_fail' | all isIrrefutable vb = []+ | otherwise = alt_fail+++ -- we are here:+ --+ -- case scrut of+ -- ...+ -- _ -> let+ -- v _ = <out of line case>+ -- in case scrut of -- we are here+ -- ...+ --+ in Case scrut+ (CaseAlternative vb [MkUnguarded (desugarGuard gs e alt_fail)]+ : alt_fail')++ return [ CaseAlternative scrut_nullbinder [MkUnguarded rhs]]++ desugarGuard :: [Guard] -> Expr -> [CaseAlternative] -> Expr+ desugarGuard [] e _ = e+ desugarGuard (ConditionGuard c : gs) e match_failed+ | isTrueExpr c = desugarGuard gs e match_failed+ | otherwise =+ Case [c]+ (CaseAlternative [LiteralBinder (BooleanLiteral True)]+ [MkUnguarded (desugarGuard gs e match_failed)] : match_failed)++ desugarGuard (PatternGuard vb g : gs) e match_failed =+ Case [g]+ (CaseAlternative [vb] [MkUnguarded (desugarGuard gs e match_failed)]+ : match_failed')+ where+ -- don't consider match_failed case if the binder is irrefutable+ match_failed' | isIrrefutable vb = []+ | otherwise = match_failed++ -- we generate a let-binding for the remaining guards+ -- and alternatives. A CaseAlternative is passed (or in+ -- fact the original case is partial non is passed) to+ -- mk_body which branches to the generated let-binding.+ desugarAltOutOfLine :: [Binder]+ -> [GuardedExpr]+ -> [CaseAlternative]+ -> ([CaseAlternative] -> Expr)+ -> m Expr+ desugarAltOutOfLine alt_binder rem_guarded rem_alts mk_body+ | Just rem_case <- mkCaseOfRemainingGuardsAndAlts = do++ desugared <- desugarCase rem_case+ rem_case_id <- freshIdent'++ let+ goto_rem_case :: Expr+ goto_rem_case = Var (Qualified Nothing rem_case_id)+ `App` Literal (BooleanLiteral True)+ alt_fail = [CaseAlternative [NullBinder] [MkUnguarded goto_rem_case]]++ pure $ Let [+ ValueDeclaration rem_case_id Private [NullBinder]+ [MkUnguarded desugared]+ ] (mk_body alt_fail)++ | otherwise+ = pure $ mk_body []+ where+ mkCaseOfRemainingGuardsAndAlts+ | not (null rem_guarded)+ = Just $ Case scrut (CaseAlternative alt_binder rem_guarded : rem_alts)+ | not (null rem_alts)+ = Just $ Case scrut rem_alts+ | otherwise+ = Nothing++ scrut_nullbinder :: [Binder]+ scrut_nullbinder = replicate (length scrut) NullBinder++ -- case expressions with a single alternative which have+ -- a NullBinder occur frequently after desugaring+ -- complex guards. This function removes these superflous+ -- cases.+ optimize :: Expr -> Expr+ optimize (Case _ [CaseAlternative vb [MkUnguarded v]])+ | all isNullBinder vb = v+ where+ isNullBinder NullBinder = True+ isNullBinder (PositionedBinder _ _ b) = isNullBinder b+ isNullBinder (TypedBinder _ b) = isNullBinder b+ isNullBinder _ = False+ optimize e = e+ in do+ alts' <- desugarAlternatives alternatives+ return $ optimize (Case scrut alts')++desugarCase v = pure v++-- | -- Validates that case head and binder lengths match. -- validateCases :: forall m. (MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]@@ -47,12 +262,12 @@ (f, _, _) = everywhereOnValuesM return validate return validate :: Expr -> m Expr- validate c@(Case vs alts) = do+ validate (Case vs alts) = do let l = length vs alts' = filter ((l /=) . length . caseAlternativeBinders) alts unless (null alts') $ throwError . MultipleErrors $ fmap (altError l) (caseAlternativeBinders <$> alts')- return c+ desugarCase (Case vs alts) validate other = return other altError :: Int -> [Binder] -> ErrorMessage@@ -72,11 +287,17 @@ (f, _, _) = everywhereOnValuesM return replace return replace :: Expr -> m Expr- replace (Abs (Right binder) val) = do+ replace (Abs (stripPositioned -> (VarBinder i)) val) =+ pure (Abs (VarBinder i) val)+ replace (Abs binder val) = do ident <- freshIdent'- return $ Abs (Left ident) $ Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right val)]+ return $ Abs (VarBinder ident) $ Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded val]] replace other = return other +stripPositioned :: Binder -> Binder+stripPositioned (PositionedBinder _ _ binder) = stripPositioned binder+stripPositioned binder = binder+ -- | -- Replace all top-level binders with case expressions. --@@ -88,8 +309,7 @@ (:) <$> (TypeInstanceDeclaration name constraints className tys <$> traverseTypeInstanceBody desugarCases ds) <*> desugarRest rest desugarRest (ValueDeclaration name nameKind bs result : rest) = let (_, f, _) = everywhereOnValuesTopDownM return go return- f' (Left gs) = Left <$> mapM (pairM return f) gs- f' (Right v) = Right <$> f v+ f' = mapM (\(GuardedExpr gs e) -> GuardedExpr gs <$> f e) in (:) <$> (ValueDeclaration name nameKind bs <$> f' result) <*> desugarRest rest where go (Let ds val') = Let <$> desugarCases ds <*> pure val'@@ -107,30 +327,27 @@ inSameGroup _ _ = False toDecls :: forall m. (MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]-toDecls [ValueDeclaration ident nameKind bs (Right val)] | all isVarBinder bs = do+toDecls [ValueDeclaration ident nameKind bs [MkUnguarded val]] | all isIrrefutable bs = do args <- mapM fromVarBinder bs- let body = foldr (Abs . Left) val args- guardWith (errorMessage (OverlappingArgNames (Just ident))) $ length (nub args) == length args- return [ValueDeclaration ident nameKind [] (Right body)]+ let body = foldr (Abs . VarBinder) val args+ guardWith (errorMessage (OverlappingArgNames (Just ident))) $ length (ordNub args) == length args+ return [ValueDeclaration ident nameKind [] [MkUnguarded body]] where- isVarBinder :: Binder -> Bool- isVarBinder NullBinder = True- isVarBinder (VarBinder _) = True- isVarBinder (PositionedBinder _ _ b) = isVarBinder b- isVarBinder (TypedBinder _ b) = isVarBinder b- isVarBinder _ = False- fromVarBinder :: Binder -> m Ident fromVarBinder NullBinder = freshIdent' fromVarBinder (VarBinder name) = return name fromVarBinder (PositionedBinder _ _ b) = fromVarBinder b fromVarBinder (TypedBinder _ b) = fromVarBinder b fromVarBinder _ = internalError "fromVarBinder: Invalid argument"-toDecls ds@(ValueDeclaration ident _ bs result : _) = do+toDecls ds@(ValueDeclaration ident _ bs (result : _) : _) = do let tuples = map toTuple ds++ isGuarded (MkUnguarded _) = False+ isGuarded _ = True+ unless (all ((== length bs) . length . fst) tuples) $ throwError . errorMessage $ ArgListLengthsDiffer ident- unless (not (null bs) || isLeft result) $+ unless (not (null bs) || isGuarded result) $ throwError . errorMessage $ DuplicateValueDeclaration ident caseDecl <- makeCaseDeclaration ident tuples return [caseDecl]@@ -139,12 +356,12 @@ return (PositionedDeclaration pos com d' : ds') toDecls ds = return ds -toTuple :: Declaration -> ([Binder], Either [(Guard, Expr)] Expr)+toTuple :: Declaration -> ([Binder], [GuardedExpr]) toTuple (ValueDeclaration _ _ bs result) = (bs, result) toTuple (PositionedDeclaration _ _ d) = toTuple d toTuple _ = internalError "Not a value declaration" -makeCaseDeclaration :: forall m. (MonadSupply m) => Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> m Declaration+makeCaseDeclaration :: forall m. (MonadSupply m) => Ident -> [([Binder], [GuardedExpr])] -> m Declaration makeCaseDeclaration ident alternatives = do let namedArgs = map findName . fst <$> alternatives argNames = foldl1 resolveNames namedArgs@@ -153,8 +370,10 @@ else replicateM (length argNames) freshIdent' let vars = map (Var . Qualified Nothing) args binders = [ CaseAlternative bs result | (bs, result) <- alternatives ]- value = foldr (Abs . Left) (Case vars binders) args- return $ ValueDeclaration ident Public [] (Right value)+ case_ <- desugarCase (Case vars binders)+ let value = foldr (Abs . VarBinder) case_ args++ return $ ValueDeclaration ident Public [] [MkUnguarded value] where -- We will construct a table of potential names. -- VarBinders will become Just _ which is a potential name.@@ -167,8 +386,8 @@ -- We still have to make sure the generated names are unique, or else -- we will end up constructing an invalid function.- allUnique :: (Eq a) => [a] -> Bool- allUnique xs = length xs == length (nub xs)+ allUnique :: (Ord a) => [a] -> Bool+ allUnique xs = length xs == length (ordNub xs) argName :: Maybe Ident -> m Ident argName (Just name) = return name
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -1,31 +1,28 @@--- |--- This module implements the desugaring pass which replaces do-notation statements with+-- | This module implements the desugaring pass which replaces do-notation statements with -- appropriate calls to bind.----module Language.PureScript.Sugar.DoNotation (desugarDoModule) where -import Prelude.Compat+{-# LANGUAGE PatternGuards #-} -import Control.Monad.Error.Class (MonadError(..))-import Control.Monad.Supply.Class+module Language.PureScript.Sugar.DoNotation (desugarDoModule) where -import Language.PureScript.AST-import Language.PureScript.Crash-import Language.PureScript.Errors-import Language.PureScript.Names+import Prelude.Compat++import Control.Monad.Error.Class (MonadError(..))+import Control.Monad.Supply.Class+import Data.Monoid (First(..))+import Language.PureScript.AST+import Language.PureScript.Crash+import Language.PureScript.Errors+import Language.PureScript.Names import qualified Language.PureScript.Constants as C --- |--- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with+-- | Replace all @DoNotationBind@ and @DoNotationValue@ constructors with -- applications of the bind function in scope, and all @DoNotationLet@ -- constructors with let expressions.--- desugarDoModule :: forall m. (MonadSupply m, MonadError MultipleErrors m) => Module -> m Module desugarDoModule (Module ss coms mn ds exts) = Module ss coms mn <$> parU ds desugarDo <*> pure exts --- |--- Desugar a single do statement---+-- | Desugar a single do statement desugarDo :: forall m. (MonadSupply m, MonadError MultipleErrors m) => Declaration -> m Declaration desugarDo (PositionedDeclaration pos com d) = PositionedDeclaration pos com <$> rethrowWithPosition pos (desugarDo d) desugarDo d =@@ -35,6 +32,9 @@ bind :: Expr bind = Var (Qualified Nothing (Ident C.bind)) + discard :: Expr+ discard = Var (Qualified Nothing (Ident C.discard))+ replace :: Expr -> m Expr replace (Do els) = go els replace (PositionedValue pos com v) = PositionedValue pos com <$> rethrowWithPosition pos (replace v)@@ -45,23 +45,25 @@ go [DoNotationValue val] = return val go (DoNotationValue val : rest) = do rest' <- go rest- return $ App (App bind val) (Abs (Left (Ident C.__unused)) rest')+ return $ App (App discard val) (Abs (VarBinder (Ident C.__unused)) rest') go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind- go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest)- go (DoNotationBind b _ : _) | Ident C.bind `elem` binderNames b =- throwError . errorMessage $ CannotUseBindWithDo+ go (DoNotationBind b _ : _) | First (Just ident) <- foldMap fromIdent (binderNames b) =+ throwError . errorMessage $ CannotUseBindWithDo (Ident ident)+ where+ fromIdent (Ident i) | i `elem` [ C.bind, C.discard ] = First (Just i)+ fromIdent _ = mempty go (DoNotationBind (VarBinder ident) val : rest) = do rest' <- go rest- return $ App (App bind val) (Abs (Left ident) rest')+ return $ App (App bind val) (Abs (VarBinder ident) rest') go (DoNotationBind binder val : rest) = do rest' <- go rest ident <- freshIdent'- return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right rest')]))+ return $ App (App bind val) (Abs (VarBinder ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded rest']])) go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet go (DoNotationLet ds : rest) = do let checkBind :: Declaration -> m ()- checkBind (ValueDeclaration (Ident name) _ _ _)- | name == C.bind = throwError . errorMessage $ CannotUseBindWithDo+ checkBind (ValueDeclaration i@(Ident name) _ _ _)+ | name `elem` [ C.bind, C.discard ] = throwError . errorMessage $ CannotUseBindWithDo i checkBind (PositionedDeclaration pos _ decl) = rethrowWithPosition pos (checkBind decl) checkBind _ = pure () mapM_ checkBind ds
+ src/Language/PureScript/Sugar/LetPattern.hs view
@@ -0,0 +1,47 @@+-- |+-- This module implements the desugaring pass which replaces patterns in let-in+-- expressions with appropriate case expressions.+--+module Language.PureScript.Sugar.LetPattern (desugarLetPatternModule) where++import Prelude.Compat++import Language.PureScript.AST++-- |+-- Replace every @BoundValueDeclaration@ in @Let@ expressions with @Case@+-- expressions.+--+desugarLetPatternModule :: Module -> Module+desugarLetPatternModule (Module ss coms mn ds exts) = Module ss coms mn (map desugarLetPattern ds) exts++-- |+-- Desugar a single let expression+--+desugarLetPattern :: Declaration -> Declaration+desugarLetPattern (PositionedDeclaration pos com d) = PositionedDeclaration pos com $ desugarLetPattern d+desugarLetPattern decl =+ let (f, _, _) = everywhereOnValues id replace id+ in f decl+ where+ replace :: Expr -> Expr+ replace (Let ds e) = go ds e+ replace other = other++ go :: [Declaration]+ -- ^ Declarations to desugar+ -> Expr+ -- ^ The original let-in result expression+ -> Expr+ go [] e = e+ go (pd@(PositionedDeclaration pos com d) : ds) e =+ case d of+ BoundValueDeclaration {} -> PositionedValue pos com $ go (d:ds) e+ _ -> append pd $ go ds e+ go (BoundValueDeclaration binder boundE : ds) e =+ Case [boundE] [CaseAlternative [binder] [MkUnguarded $ go ds e]]+ go (d:ds) e = append d $ go ds e++ append :: Declaration -> Expr -> Expr+ append d (Let ds e) = Let (d:ds) e+ append d e = Let [d] e
src/Language/PureScript/Sugar/Names.hs view
@@ -9,6 +9,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Arrow (first) import Control.Monad@@ -16,7 +17,6 @@ import Control.Monad.State.Lazy import Control.Monad.Writer (MonadWriter(..), censor) -import Data.List (nub) import Data.Maybe (fromMaybe, mapMaybe) import qualified Data.Map as M import qualified Data.Set as S@@ -65,12 +65,11 @@ externsEnv :: Env -> ExternsFile -> m Env externsEnv env ExternsFile{..} = do let members = Exports{..}- ss = internalModuleSourceSpan "<Externs>"- env' = M.insert efModuleName (ss, primImports, members) env+ env' = M.insert efModuleName (efSourceSpan, primImports, members) env fromEFImport (ExternsImport mn mt qmn) = (mn, [(Nothing, Just mt, qmn)]) imps <- foldM (resolveModuleImport env') primImports (map fromEFImport efImports)- exps <- resolveExports env' ss efModuleName imps members efExports- return $ M.insert efModuleName (ss, imps, exps) env+ exps <- resolveExports env' efSourceSpan efModuleName imps members efExports+ return $ M.insert efModuleName (efSourceSpan, imps, exps) env where exportedTypes :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName)@@ -202,11 +201,11 @@ -> m ((Maybe SourceSpan, [Ident]), Expr) updateValue (_, bound) v@(PositionedValue pos' _ _) = return ((Just pos', bound), v)- updateValue (pos, bound) (Abs (Left arg) val') =- return ((pos, arg : bound), Abs (Left arg) val')+ updateValue (pos, bound) (Abs (VarBinder arg) val') =+ return ((pos, arg : bound), Abs (VarBinder arg) val') updateValue (pos, bound) (Let ds val') = do let args = mapMaybe letBoundVariable ds- unless (length (nub args) == length args) $+ unless (length (ordNub args) == length args) $ maybe id rethrowWithPosition pos $ throwError . errorMessage $ OverlappingNamesInLet return ((pos, args ++ bound), Let ds val')@@ -242,8 +241,16 @@ :: (Maybe SourceSpan, [Ident]) -> CaseAlternative -> m ((Maybe SourceSpan, [Ident]), CaseAlternative)- updateCase (pos, bound) c@(CaseAlternative bs _) =- return ((pos, concatMap binderNames bs ++ bound), c)+ updateCase (pos, bound) c@(CaseAlternative bs gs) =+ return ((pos, concatMap binderNames bs ++ updateGuard gs ++ bound), c)+ where+ updateGuard :: [GuardedExpr] -> [Ident]+ updateGuard [] = []+ updateGuard (GuardedExpr g _ : xs) =+ concatMap updatePatGuard g ++ updateGuard xs+ where+ updatePatGuard (PatternGuard b _) = binderNames b+ updatePatGuard _ = [] letBoundVariable :: Declaration -> Maybe Ident letBoundVariable (ValueDeclaration ident _ _ _) = Just ident@@ -269,7 +276,7 @@ updateType :: Type -> m Type updateType (TypeOp name) = TypeOp <$> updateTypeOpName name pos updateType (TypeConstructor name) = TypeConstructor <$> updateTypeName name pos- updateType (ConstrainedType cs t) = ConstrainedType <$> traverse updateInConstraint cs <*> pure t+ updateType (ConstrainedType c t) = ConstrainedType <$> updateInConstraint c <*> pure t updateType (KindedType t k) = KindedType t <$> updateKindsEverywhere pos k updateType t = return t updateInConstraint :: Constraint -> m Constraint@@ -342,11 +349,8 @@ -- in scope, we throw an error. (Just options, _) -> do (mnNew, mnOrig) <- checkImportConflicts mn toName options- modify $ \result ->- M.insert- mnNew- (maybe [fmap toName qname] (fmap toName qname :) (mnNew `M.lookup` result))- result+ modify $ \usedImports ->+ M.insertWith (++) mnNew [fmap toName qname] usedImports return $ Qualified (Just mnOrig) name -- If the name wasn't found in our imports but was qualified then we need
src/Language/PureScript/Sugar/Names/Common.hs view
@@ -1,12 +1,13 @@ module Language.PureScript.Sugar.Names.Common (warnDuplicateRefs) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad.Writer (MonadWriter(..)) import Data.Foldable (for_) import Data.Function (on)-import Data.List (nub, nubBy, (\\))+import Data.List (nubBy, (\\)) import Data.Maybe (mapMaybe) import Language.PureScript.AST@@ -52,7 +53,7 @@ extractCtors :: SourceSpan -> DeclarationRef -> Maybe [(SourceSpan, Name)] extractCtors _ (PositionedDeclarationRef pos' _ ref) = extractCtors pos' ref extractCtors pos' (TypeRef _ (Just dctors)) =- let dupes = dctors \\ nub dctors+ let dupes = dctors \\ ordNub dctors in if null dupes then Nothing else Just $ ((pos',) . DctorName) <$> dupes extractCtors _ _ = Nothing
src/Language/PureScript/Sugar/ObjectWildcards.hs view
@@ -37,27 +37,27 @@ | b' <- stripPositionInfo b , BinaryNoParens op val u <- b' , isAnonymousArgument u = do arg <- freshIdent'- return $ Abs (Left arg) $ App (App op val) (Var (Qualified Nothing arg))+ return $ Abs (VarBinder arg) $ App (App op val) (Var (Qualified Nothing arg)) | b' <- stripPositionInfo b , BinaryNoParens op u val <- b' , isAnonymousArgument u = do arg <- freshIdent'- return $ Abs (Left arg) $ App (App op (Var (Qualified Nothing arg))) val+ return $ Abs (VarBinder arg) $ App (App op (Var (Qualified Nothing arg))) val desugarExpr (Literal (ObjectLiteral ps)) = wrapLambdaAssoc (Literal . ObjectLiteral) ps desugarExpr (ObjectUpdateNested obj ps) = transformNestedUpdate obj ps desugarExpr (Accessor prop u) | Just props <- peelAnonAccessorChain u = do arg <- freshIdent'- return $ Abs (Left arg) $ foldr Accessor (argToExpr arg) (prop:props)+ return $ Abs (VarBinder arg) $ foldr Accessor (argToExpr arg) (prop:props) desugarExpr (Case args cas) | any isAnonymousArgument args = do argIdents <- forM args freshIfAnon let args' = zipWith (`maybe` argToExpr) args argIdents- return $ foldr (Abs . Left) (Case args' cas) (catMaybes argIdents)+ return $ foldr (Abs . VarBinder) (Case args' cas) (catMaybes argIdents) desugarExpr (IfThenElse u t f) | any isAnonymousArgument [u, t, f] = do u' <- freshIfAnon u t' <- freshIfAnon t f' <- freshIfAnon f let if_ = IfThenElse (maybe u argToExpr u') (maybe t argToExpr t') (maybe f argToExpr f')- return $ foldr (Abs . Left) if_ (catMaybes [u', t', f'])+ return $ foldr (Abs . VarBinder) if_ (catMaybes [u', t', f']) desugarExpr e = return e transformNestedUpdate :: Expr -> PathTree Expr -> m Expr@@ -67,10 +67,10 @@ val <- freshIdent' let valExpr = argToExpr val if isAnonymousArgument obj- then Abs (Left val) <$> wrapLambda (buildUpdates valExpr) ps+ then Abs (VarBinder val) <$> wrapLambda (buildUpdates valExpr) ps else wrapLambda (buildLet val . buildUpdates valExpr) ps where- buildLet val = Let [ValueDeclaration val Public [] (Right obj)]+ buildLet val = Let [ValueDeclaration val Public [] [MkUnguarded obj]] -- recursively build up the nested `ObjectUpdate` expressions buildUpdates :: Expr -> PathTree Expr -> Expr@@ -87,7 +87,7 @@ wrapLambda :: forall t. Traversable t => (t Expr -> Expr) -> t Expr -> m Expr wrapLambda mkVal ps = do args <- traverse processExpr ps- return $ foldr (Abs . Left) (mkVal (snd <$> args)) (catMaybes $ toList (fst <$> args))+ return $ foldr (Abs . VarBinder) (mkVal (snd <$> args)) (catMaybes $ toList (fst <$> args)) where processExpr :: Expr -> m (Maybe Ident, Expr) processExpr e = do
src/Language/PureScript/Sugar/TypeClasses.hs view
@@ -10,29 +10,26 @@ import Prelude.Compat -import Language.PureScript.Crash-import Language.PureScript.Environment-import Language.PureScript.Errors hiding (isExported)-import Language.PureScript.Kinds-import Language.PureScript.Names-import Language.PureScript.Externs-import Language.PureScript.Sugar.CaseDeclarations-import Control.Monad.Supply.Class-import Language.PureScript.Types-import Language.PureScript.Label (Label(..))-import Language.PureScript.PSString (mkString)--import qualified Language.PureScript.Constants as C--import Control.Arrow (first, second)-import Control.Monad.Error.Class (MonadError(..))-import Control.Monad.State-import Data.List ((\\), find, sortBy)-import Data.Maybe (catMaybes, mapMaybe, isJust)+import Control.Arrow (first, second)+import Control.Monad.Error.Class (MonadError(..))+import Control.Monad.State+import Control.Monad.Supply.Class+import Data.List ((\\), find, sortBy) import qualified Data.Map as M-import Data.Monoid ((<>))-import Data.Text (Text)-import qualified Data.Text as T+import Data.Maybe (catMaybes, mapMaybe, isJust)+import Data.Text (Text)+import qualified Language.PureScript.Constants as C+import Language.PureScript.Crash+import Language.PureScript.Environment+import Language.PureScript.Errors hiding (isExported)+import Language.PureScript.Externs+import Language.PureScript.Kinds+import Language.PureScript.Label (Label(..))+import Language.PureScript.Names+import Language.PureScript.PSString (mkString)+import Language.PureScript.Sugar.CaseDeclarations+import Language.PureScript.Types+import Language.PureScript.TypeClassDictionaries (superclassName) type MemberMap = M.Map (ModuleName, ProperName 'ClassName) TypeClassData @@ -126,7 +123,7 @@ -- <TypeClassDeclaration Sub ...> -- -- type Sub a = { sub :: a--- , "__superclass_Foo_0" :: {} -> Foo a+-- , "Foo0" :: {} -> Foo a -- } -- -- -- As with `foo` above, this type is unchecked at the declaration@@ -135,7 +132,7 @@ -- -- subString :: {} -> Sub String -- subString _ = { sub: "",--- , "__superclass_Foo_0": \_ -> <DeferredDictionary Foo String>+-- , "Foo0": \_ -> <DeferredDictionary Foo String> -- } -- -- and finally as the generated javascript:@@ -158,8 +155,8 @@ -- return new Foo(map(foo(__dict_Foo_15))); -- }; ----- function Sub(__superclass_Foo_0, sub) {--- this["__superclass_Foo_0"] = __superclass_Foo_0;+-- function Sub(Foo0, sub) {+-- this["Foo0"] = Foo0; -- this.sub = sub; -- }; --@@ -189,8 +186,8 @@ return (expRef name className tys, [d, dictDecl]) go d@(TypeInstanceDeclaration name deps className tys (NewtypeInstanceWithDictionary dict)) = do let dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys- constrainedTy = quantify (if null deps then dictTy else ConstrainedType deps dictTy)- return (expRef name className tys, [d, ValueDeclaration name Private [] (Right (TypedValue True dict constrainedTy))])+ constrainedTy = quantify (foldr ConstrainedType dictTy deps)+ return (expRef name className tys, [d, ValueDeclaration name Private [] [MkUnguarded (TypedValue True dict constrainedTy)]]) go (PositionedDeclaration pos com d) = do (dr, ds) <- rethrowWithPosition pos $ desugarDecl mn exps d return (dr, map (PositionedDeclaration pos com) ds)@@ -252,9 +249,11 @@ -> Declaration typeClassMemberToDictionaryAccessor mn name args (TypeDeclaration ident ty) = let className = Qualified (Just mn) name- in ValueDeclaration ident Private [] $ Right $- TypedValue False (TypeClassDictionaryAccessor className ident) $- moveQuantifiersToFront (quantify (ConstrainedType [Constraint className (map (TypeVar . fst) args) Nothing] ty))+ in ValueDeclaration ident Private [] $+ [MkUnguarded (+ TypedValue False (TypeClassDictionaryAccessor className ident) $+ moveQuantifiersToFront (quantify (ConstrainedType (Constraint className (map (TypeVar . fst) args) Nothing) ty))+ )] typeClassMemberToDictionaryAccessor mn name args (PositionedDeclaration pos com d) = PositionedDeclaration pos com $ typeClassMemberToDictionaryAccessor mn name args d typeClassMemberToDictionaryAccessor _ _ _ _ = internalError "Invalid declaration in type class definition"@@ -294,16 +293,16 @@ -- The type is a record type, but depending on type instance dependencies, may be constrained. -- The dictionary itself is a record literal. let superclasses = superClassDictionaryNames typeClassSuperclasses `zip`- [ Abs (Left (Ident C.__unused)) (DeferredDictionary superclass tyArgs)+ [ Abs (VarBinder (Ident C.__unused)) (DeferredDictionary superclass tyArgs) | (Constraint superclass suTyArgs _) <- typeClassSuperclasses , let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs ] let props = Literal $ ObjectLiteral $ map (first mkString) (members ++ superclasses) dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys- constrainedTy = quantify (if null deps then dictTy else ConstrainedType deps dictTy)+ constrainedTy = quantify (foldr ConstrainedType dictTy deps) dict = TypeClassDictionaryConstructorApp className props- result = ValueDeclaration name Private [] (Right (TypedValue True dict constrainedTy))+ result = ValueDeclaration name Private [] [MkUnguarded (TypedValue True dict constrainedTy)] return result where@@ -315,7 +314,7 @@ declName _ = Nothing memberToValue :: [(Ident, Type)] -> Declaration -> Desugar m Expr- memberToValue tys' (ValueDeclaration ident _ [] (Right val)) = do+ memberToValue tys' (ValueDeclaration ident _ [] [MkUnguarded val]) = do _ <- maybe (throwError . errorMessage $ ExtraneousClassMember ident className) return $ lookup ident tys' return val memberToValue tys' (PositionedDeclaration pos com d) = rethrowWithPosition pos $ do@@ -331,6 +330,6 @@ superClassDictionaryNames :: [Constraint] -> [Text] superClassDictionaryNames supers =- [ C.__superclass_ <> showQualified runProperName pn <> "_" <> T.pack (show (index :: Integer))+ [ superclassName pn index | (index, Constraint pn _ _) <- zip [0..] supers ]
src/Language/PureScript/Sugar/TypeClasses/Deriving.hs view
@@ -64,43 +64,61 @@ -> [Declaration] -> Declaration -> m Declaration-deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className tys@[ty] DerivedInstance)+deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className tys DerivedInstance) | className == Qualified (Just dataGeneric) (ProperName C.generic)- , Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor ty- , mn == fromMaybe mn mn'- = TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveGeneric mn syns ds tyCon args+ = case tys of+ [ty] | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor ty+ , mn == fromMaybe mn mn'+ -> TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveGeneric mn syns ds tyCon args+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys ty+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataEq) (ProperName "Eq")- , Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty- , mn == fromMaybe mn mn'- = TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveEq mn syns ds tyCon+ = case tys of+ [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty+ , mn == fromMaybe mn mn'+ -> TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveEq mn syns ds tyCon+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys ty+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataOrd) (ProperName "Ord")- , Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty- , mn == fromMaybe mn mn'- = TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveOrd mn syns ds tyCon+ = case tys of+ [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty+ , mn == fromMaybe mn mn'+ -> TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveOrd mn syns ds tyCon+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys ty+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataFunctor) (ProperName "Functor")- , Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty- , mn == fromMaybe mn mn'- = TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveFunctor mn syns ds tyCon-deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className [wrappedTy, unwrappedTy] DerivedInstance)+ = case tys of+ [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty+ , mn == fromMaybe mn mn'+ -> TypeInstanceDeclaration nm deps className tys . ExplicitInstance <$> deriveFunctor mn syns ds tyCon+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys ty+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataNewtype) (ProperName "Newtype")- , Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor wrappedTy- , mn == fromMaybe mn mn'- = do (inst, actualUnwrappedTy) <- deriveNewtype mn syns ds tyCon args unwrappedTy- return $ TypeInstanceDeclaration nm deps className [wrappedTy, actualUnwrappedTy] (ExplicitInstance inst)-deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className [actualTy, repTy] DerivedInstance)+ = case tys of+ [wrappedTy, unwrappedTy]+ | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor wrappedTy+ , mn == fromMaybe mn mn'+ -> do (inst, actualUnwrappedTy) <- deriveNewtype mn syns ds tyCon args unwrappedTy+ return $ TypeInstanceDeclaration nm deps className [wrappedTy, actualUnwrappedTy] (ExplicitInstance inst)+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys wrappedTy+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 2 | className == Qualified (Just dataGenericRep) (ProperName C.generic)- , Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor actualTy- , mn == fromMaybe mn mn'- = do (inst, inferredRepTy) <- deriveGenericRep mn syns ds tyCon args repTy- return $ TypeInstanceDeclaration nm deps className [actualTy, inferredRepTy] (ExplicitInstance inst)-deriveInstance _ _ _ (TypeInstanceDeclaration _ _ className tys DerivedInstance)- = throwError . errorMessage $ CannotDerive className tys-deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className tys@(_ : _) NewtypeInstance)- | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor (last tys)- , mn == fromMaybe mn mn'- = TypeInstanceDeclaration nm deps className tys . NewtypeInstanceWithDictionary <$> deriveNewtypeInstance syns className ds tys tyCon args-deriveInstance _ _ _ (TypeInstanceDeclaration _ _ className tys NewtypeInstance)- = throwError . errorMessage $ InvalidNewtypeInstance className tys+ = case tys of+ [actualTy, repTy]+ | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor actualTy+ , mn == fromMaybe mn mn'+ -> do (inst, inferredRepTy) <- deriveGenericRep mn syns ds tyCon args repTy+ return $ TypeInstanceDeclaration nm deps className [actualTy, inferredRepTy] (ExplicitInstance inst)+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys actualTy+ _ -> throwError . errorMessage $ InvalidDerivedInstance className tys 2+ | otherwise = throwError . errorMessage $ CannotDerive className tys+deriveInstance mn syns ds (TypeInstanceDeclaration nm deps className tys NewtypeInstance) =+ case tys of+ _ : _ | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor (last tys)+ , mn == fromMaybe mn mn'+ -> TypeInstanceDeclaration nm deps className tys . NewtypeInstanceWithDictionary <$> deriveNewtypeInstance syns className ds tys tyCon args+ | otherwise -> throwError . errorMessage $ ExpectedTypeConstructor className tys (last tys)+ _ -> throwError . errorMessage $ InvalidNewtypeInstance className tys deriveInstance mn syns ds (PositionedDeclaration pos com d) = PositionedDeclaration pos com <$> deriveInstance mn syns ds d deriveInstance _ _ _ e = return e @@ -177,6 +195,9 @@ dataFunctor :: ModuleName dataFunctor = ModuleName [ ProperName "Data", ProperName "Functor" ] +unguarded :: Expr -> [GuardedExpr]+unguarded e = [MkUnguarded e]+ deriveGeneric :: forall m. (MonadError MultipleErrors m, MonadSupply m) => ModuleName@@ -189,10 +210,10 @@ tyCon <- findTypeDecl tyConNm ds toSpine <- mkSpineFunction tyCon fromSpine <- mkFromSpineFunction tyCon- let toSignature = mkSignatureFunction tyCon dargs- return [ ValueDeclaration (Ident C.toSpine) Public [] (Right toSpine)- , ValueDeclaration (Ident C.fromSpine) Public [] (Right fromSpine)- , ValueDeclaration (Ident C.toSignature) Public [] (Right toSignature)+ toSignature <- mkSignatureFunction tyCon dargs+ return [ ValueDeclaration (Ident C.toSpine) Public [] (unguarded toSpine)+ , ValueDeclaration (Ident C.fromSpine) Public [] (unguarded fromSpine)+ , ValueDeclaration (Ident C.toSignature) Public [] (unguarded toSignature) ] where mkSpineFunction :: Declaration -> m Expr@@ -214,10 +235,11 @@ App (prodConstructor (Literal . StringLiteral . mkString . showQualified runProperName $ Qualified (Just mn) ctorName)) . Literal . ArrayLiteral $ zipWith toSpineFun (map (Var . Qualified Nothing) idents) tys'- return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (Right caseResult)+ return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (unguarded caseResult) toSpineFun :: Expr -> Type -> Expr- toSpineFun i r | Just rec <- objectType r =+ toSpineFun i r | Just rec <- objectType r+ , Just fields <- decomposeRec rec = lamNull . recordConstructor . Literal . ArrayLiteral . map (\((Label str),typ) ->@@ -226,13 +248,13 @@ , ("recValue", toSpineFun (Accessor str i) typ) ] )- $ decomposeRec rec+ $ fields toSpineFun i _ = lamNull $ App (mkGenVar (Ident C.toSpine)) i mkSpineFunction (PositionedDeclaration _ _ d) = mkSpineFunction d mkSpineFunction _ = internalError "mkSpineFunction: expected DataDeclaration" - mkSignatureFunction :: Declaration -> [Type] -> Expr- mkSignatureFunction (DataDeclaration _ name tyArgs args) classArgs = lamNull . mkSigProd $ map mkProdClause args+ mkSignatureFunction :: Declaration -> [Type] -> m Expr+ mkSignatureFunction (DataDeclaration _ name tyArgs args) classArgs = lamNull . mkSigProd <$> mapM mkProdClause args where mkSigProd :: [Expr] -> Expr mkSigProd =@@ -250,21 +272,23 @@ proxy :: Type -> Type proxy = TypeApp (TypeConstructor (Qualified (Just typesProxy) (ProperName "Proxy"))) - mkProdClause :: (ProperName 'ConstructorName, [Type]) -> Expr- mkProdClause (ctorName, tys) =- Literal $ ObjectLiteral+ mkProdClause :: (ProperName 'ConstructorName, [Type]) -> m Expr+ mkProdClause (ctorName, tys) = do+ tys' <- mapM (replaceAllTypeSynonymsM syns) tys+ return $ Literal $ ObjectLiteral [ ("sigConstructor", Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName))))- , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys)+ , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys') ] mkProductSignature :: Type -> Expr- mkProductSignature r | Just rec <- objectType r =+ mkProductSignature r | Just rec <- objectType r+ , Just fields <- decomposeRec rec = lamNull . mkSigRec $ [ Literal $ ObjectLiteral [ ("recLabel", Literal (StringLiteral str)) , ("recValue", mkProductSignature typ) ]- | ((Label str), typ) <- decomposeRec rec+ | ((Label str), typ) <- fields ] mkProductSignature typ = lamNull $ App (mkGenVar (Ident C.toSignature)) (TypedValue False (mkGenVar (Ident "anyProxy")) (proxy typ))@@ -292,6 +316,7 @@ mkAlternative :: (ProperName 'ConstructorName, [Type]) -> m CaseAlternative mkAlternative (ctorName, tys) = do idents <- replicateM (length tys) freshIdent'+ tys' <- mapM (replaceAllTypeSynonymsM syns) tys return $ CaseAlternative [ prodBinder@@ -299,21 +324,22 @@ , LiteralBinder (ArrayLiteral (map VarBinder idents)) ] ]- . Right+ . unguarded $ liftApplicative (mkJust $ Constructor (Qualified (Just mn) ctorName))- (zipWith fromSpineFun (map (Var . Qualified Nothing) idents) tys)+ (zipWith fromSpineFun (map (Var . Qualified Nothing) idents) tys') addCatch :: [CaseAlternative] -> [CaseAlternative] addCatch = (++ [catchAll]) where- catchAll = CaseAlternative [NullBinder] (Right mkNothing)+ catchAll = CaseAlternative [NullBinder] (unguarded mkNothing) fromSpineFun :: Expr -> Type -> Expr fromSpineFun e r | Just rec <- objectType r- = App (lamCase (Ident "r") [ mkRecCase (decomposeRec rec)- , CaseAlternative [NullBinder] (Right mkNothing)+ , Just fields <- decomposeRec rec+ = App (lamCase (Ident "r") [ mkRecCase fields+ , CaseAlternative [NullBinder] (unguarded mkNothing) ]) (App e unitVal) fromSpineFun e _ = App (mkGenVar (Ident C.fromSpine)) (App e unitVal)@@ -322,7 +348,7 @@ mkRecCase rs = CaseAlternative [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . labelToIdent . fst) rs)) ] ]- . Right+ . unguarded $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar $ labelToIdent x)) y) rs) mkRecFun :: [(Label, Type)] -> Expr@@ -366,19 +392,19 @@ let rep = toRepTy reps inst | null reps = -- If there are no cases, spin- [ ValueDeclaration (Ident "to") Public [] $ Right $+ [ ValueDeclaration (Ident "to") Public [] $ unguarded $ lamCase x [ CaseAlternative [NullBinder]- (Right (App toName (Var (Qualified Nothing x))))+ (unguarded (App toName (Var (Qualified Nothing x)))) ]- , ValueDeclaration (Ident "from") Public [] $ Right $+ , ValueDeclaration (Ident "from") Public [] $ unguarded $ lamCase x [ CaseAlternative [NullBinder]- (Right (App fromName (Var (Qualified Nothing x))))+ (unguarded (App fromName (Var (Qualified Nothing x)))) ] ] | otherwise =- [ ValueDeclaration (Ident "to") Public [] $ Right $+ [ ValueDeclaration (Ident "to") Public [] $ unguarded $ lamCase x (zipWith ($) (map underBinder (sumBinders (length dctors))) to)- , ValueDeclaration (Ident "from") Public [] $ Right $+ , ValueDeclaration (Ident "from") Public [] $ unguarded $ lamCase x (zipWith ($) (map underExpr (sumExprs (length dctors))) from) ] @@ -412,9 +438,9 @@ (TypeLevelString $ mkString (runProperName ctorName))) ctorTy , CaseAlternative [ ConstructorBinder constructor [matchProduct] ]- (Right (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs))+ (unguarded (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs)) , CaseAlternative [ ConstructorBinder (Qualified (Just mn) ctorName) matchCtor ]- (Right (constructor' mkProduct))+ (unguarded (constructor' mkProduct)) ) makeProduct@@ -432,25 +458,34 @@ ) makeArg :: Type -> m (Type, Binder, Expr, Binder, Expr)- makeArg arg | Just rec <- objectType arg = do- let fields = decomposeRec rec+ makeArg arg | Just rec <- objectType arg+ , Just fields <- decomposeRec rec = do fieldNames <- traverse freshIdent (map (runIdent . labelToIdent . fst) fields)- pure ( TypeApp (TypeConstructor record)- (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))- (map (\((Label name), ty) ->- TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))- , ConstructorBinder record- [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])- (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)- ]- , Literal . ObjectLiteral $- zipWith (\((Label name), _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames- , LiteralBinder . ObjectLiteral $- zipWith (\((Label name), _) ident -> (name, VarBinder ident)) fields fieldNames- , record' $- foldr1 (\e1 -> App (App (Constructor productName) e1))- (map (field' . Var . Qualified Nothing) fieldNames)- )+ case fieldNames of+ [] ->+ pure ( TypeApp (TypeConstructor record) noArgs+ , ConstructorBinder record [ NullBinder ]+ , Literal (ObjectLiteral [])+ , LiteralBinder (ObjectLiteral [])+ , record' noArgs'+ )+ _ ->+ pure ( TypeApp (TypeConstructor record)+ (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))+ (map (\((Label name), ty) ->+ TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))+ , ConstructorBinder record+ [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])+ (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)+ ]+ , Literal . ObjectLiteral $+ zipWith (\((Label name), _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames+ , LiteralBinder . ObjectLiteral $+ zipWith (\((Label name), _) ident -> (name, VarBinder ident)) fields fieldNames+ , record' $+ foldr1 (\e1 -> App (App (Constructor productName) e1))+ (map (field' . Var . Qualified Nothing) fieldNames)+ ) makeArg arg = do argName <- freshIdent "arg" pure ( TypeApp (TypeConstructor argument) arg@@ -464,8 +499,8 @@ underBinder f (CaseAlternative bs e) = CaseAlternative (map f bs) e underExpr :: (Expr -> Expr) -> CaseAlternative -> CaseAlternative- underExpr f (CaseAlternative b (Right e)) = CaseAlternative b (Right (f e))- underExpr _ _ = internalError "underExpr: expected Right"+ underExpr f (CaseAlternative b [MkUnguarded e]) = CaseAlternative b (unguarded (f e))+ underExpr _ _ = internalError "underExpr: expected unguarded alternative" toRepTy :: [Type] -> Type toRepTy [] = noCtors@@ -538,7 +573,7 @@ deriveEq mn syns ds tyConNm = do tyCon <- findTypeDecl tyConNm ds eqFun <- mkEqFunction tyCon- return [ ValueDeclaration (Ident C.eq) Public [] (Right eqFun) ]+ return [ ValueDeclaration (Ident C.eq) Public [] (unguarded eqFun) ] where mkEqFunction :: Declaration -> m Expr mkEqFunction (DataDeclaration _ _ _ args) = do@@ -559,7 +594,7 @@ | length xs /= 1 = xs ++ [catchAll] | otherwise = xs -- Avoid redundant case where- catchAll = CaseAlternative [NullBinder, NullBinder] (Right (Literal (BooleanLiteral False)))+ catchAll = CaseAlternative [NullBinder, NullBinder] (unguarded (Literal (BooleanLiteral False))) mkCtorClause :: (ProperName 'ConstructorName, [Type]) -> m CaseAlternative mkCtorClause (ctorName, tys) = do@@ -567,7 +602,7 @@ identsR <- replicateM (length tys) (freshIdent "r") tys' <- mapM (replaceAllTypeSynonymsM syns) tys let tests = zipWith3 toEqTest (map (Var . Qualified Nothing) identsL) (map (Var . Qualified Nothing) identsR) tys'- return $ CaseAlternative [caseBinder identsL, caseBinder identsR] (Right (conjAll tests))+ return $ CaseAlternative [caseBinder identsL, caseBinder identsR] (unguarded (conjAll tests)) where caseBinder idents = ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents) @@ -576,10 +611,11 @@ conjAll xs = foldl1 preludeConj xs toEqTest :: Expr -> Expr -> Type -> Expr- toEqTest l r ty | Just rec <- objectType ty =+ toEqTest l r ty | Just rec <- objectType ty+ , Just fields <- decomposeRec rec = conjAll . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ)- $ decomposeRec rec+ $ fields toEqTest l r _ = preludeEq l r deriveOrd ::@@ -592,7 +628,7 @@ deriveOrd mn syns ds tyConNm = do tyCon <- findTypeDecl tyConNm ds compareFun <- mkCompareFunction tyCon- return [ ValueDeclaration (Ident C.compare) Public [] (Right compareFun) ]+ return [ ValueDeclaration (Ident C.compare) Public [] (unguarded compareFun) ] where mkCompareFunction :: Declaration -> m Expr mkCompareFunction (DataDeclaration _ _ _ args) = do@@ -612,7 +648,7 @@ | null xs = [catchAll] -- No type constructors | otherwise = xs where- catchAll = CaseAlternative [NullBinder, NullBinder] (Right (orderingCtor "EQ"))+ catchAll = CaseAlternative [NullBinder, NullBinder] (unguarded (orderingCtor "EQ")) orderingName :: Text -> Qualified (ProperName a) orderingName = Qualified (Just (ModuleName [ProperName "Data", ProperName "Ordering"])) . ProperName@@ -635,17 +671,17 @@ extras | not isLast = [ CaseAlternative [ ConstructorBinder (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder) , NullBinder ]- (Right (orderingCtor "LT"))+ (unguarded (orderingCtor "LT")) , CaseAlternative [ NullBinder , ConstructorBinder (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder) ]- (Right (orderingCtor "GT"))+ (unguarded (orderingCtor "GT")) ] | otherwise = [] return $ CaseAlternative [ caseBinder identsL , caseBinder identsR ]- (Right (appendAll tests))+ (unguarded (appendAll tests)) : extras where@@ -655,18 +691,19 @@ appendAll [] = orderingCtor "EQ" appendAll [x] = x appendAll (x : xs) = Case [x] [ CaseAlternative [orderingBinder "LT"]- (Right (orderingCtor "LT"))+ (unguarded (orderingCtor "LT")) , CaseAlternative [orderingBinder "GT"]- (Right (orderingCtor "GT"))+ (unguarded (orderingCtor "GT")) , CaseAlternative [ NullBinder ]- (Right (appendAll xs))+ (unguarded (appendAll xs)) ] toOrdering :: Expr -> Expr -> Type -> Expr- toOrdering l r ty | Just rec <- objectType ty =+ toOrdering l r ty | Just rec <- objectType ty+ , Just fields <- decomposeRec rec = appendAll . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ)- $ decomposeRec rec+ $ fields toOrdering l r _ = ordCompare l r deriveNewtype@@ -693,13 +730,13 @@ let (ctorName, [ty]) = head dctors ty' <- replaceAllTypeSynonymsM syns ty let inst =- [ ValueDeclaration (Ident "wrap") Public [] $ Right $+ [ ValueDeclaration (Ident "wrap") Public [] $ unguarded $ Constructor (Qualified (Just mn) ctorName)- , ValueDeclaration (Ident "unwrap") Public [] $ Right $+ , ValueDeclaration (Ident "unwrap") Public [] $ unguarded $ lamCase wrappedIdent [ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) [VarBinder unwrappedIdent]]- (Right (Var (Qualified Nothing unwrappedIdent)))+ (unguarded (Var (Qualified Nothing unwrappedIdent))) ] ] subst = zipWith ((,) . fst) args tyConArgs@@ -720,7 +757,7 @@ isTypeDecl _ = False lam :: Ident -> Expr -> Expr-lam = Abs . Left+lam = Abs . VarBinder lamNull :: Expr -> Expr lamNull = lam (Ident "$q") -- TODO: use GenIdent@@ -752,9 +789,15 @@ objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec objectType _ = Nothing -decomposeRec :: Type -> [(Label, Type)]-decomposeRec = sortBy (comparing fst) . go- where go (RCons str typ typs) = (str, typ) : decomposeRec typs+decomposeRec :: Type -> Maybe [(Label, Type)]+decomposeRec = fmap (sortBy (comparing fst)) . go+ where go (RCons str typ typs) = fmap ((str, typ) :) (go typs)+ go REmpty = Just []+ go _ = Nothing++decomposeRec' :: Type -> [(Label, Type)]+decomposeRec' = sortBy (comparing fst) . go+ where go (RCons str typ typs) = (str, typ) : go typs go _ = [] deriveFunctor@@ -768,7 +811,7 @@ deriveFunctor mn syns ds tyConNm = do tyCon <- findTypeDecl tyConNm ds mapFun <- mkMapFunction tyCon- return [ ValueDeclaration (Ident C.map) Public [] (Right mapFun) ]+ return [ ValueDeclaration (Ident C.map) Public [] (unguarded mapFun) ] where mkMapFunction :: Declaration -> m Expr mkMapFunction (DataDeclaration _ _ tys ctors) = case reverse tys of@@ -788,7 +831,7 @@ let ctor = Constructor (Qualified (Just mn) ctorName) rebuilt = foldl App ctor args caseBinder = ConstructorBinder (Qualified (Just mn) ctorName) (VarBinder <$> idents)- return $ CaseAlternative [caseBinder] (Right rebuilt)+ return $ CaseAlternative [caseBinder] (unguarded rebuilt) where fVar = mkVar f mapVar = mkVarMn (Just dataFunctor) (Ident C.map)@@ -803,7 +846,7 @@ -- records goType recTy | Just row <- objectType recTy =- traverse buildUpdate (decomposeRec row) >>= (traverse buildRecord . justUpdates)+ traverse buildUpdate (decomposeRec' row) >>= (traverse buildRecord . justUpdates) where justUpdates :: [Maybe (Label, Expr)] -> Maybe [(Label, Expr)] justUpdates = foldMap (fmap return)
src/Language/PureScript/Sugar/TypeDeclarations.hs view
@@ -14,7 +14,6 @@ import Language.PureScript.Names import Language.PureScript.Environment import Language.PureScript.Errors-import Language.PureScript.Traversals -- | -- Replace all top level type declarations in a module with type annotations@@ -35,10 +34,10 @@ return (PositionedDeclaration pos com d' : rest') desugarTypeDeclarations (TypeDeclaration name' ty : d : rest) = do (_, nameKind, val) <- fromValueDeclaration d- desugarTypeDeclarations (ValueDeclaration name' nameKind [] (Right (TypedValue True val ty)) : rest)+ desugarTypeDeclarations (ValueDeclaration name' nameKind [] [MkUnguarded (TypedValue True val ty)] : rest) where fromValueDeclaration :: Declaration -> m (Ident, NameKind, Expr)- fromValueDeclaration (ValueDeclaration name'' nameKind [] (Right val))+ fromValueDeclaration (ValueDeclaration name'' nameKind [] [MkUnguarded val]) | name' == name'' = return (name'', nameKind, val) fromValueDeclaration (PositionedDeclaration pos com d') = do (ident, nameKind, val) <- rethrowWithPosition pos $ fromValueDeclaration d'@@ -49,8 +48,7 @@ throwError . errorMessage $ OrphanTypeDeclaration name' desugarTypeDeclarations (ValueDeclaration name' nameKind bs val : rest) = do let (_, f, _) = everywhereOnValuesTopDownM return go return- f' (Left gs) = Left <$> mapM (pairM return f) gs- f' (Right v) = Right <$> f v+ f' = mapM (\(GuardedExpr g e) -> GuardedExpr g <$> f e) (:) <$> (ValueDeclaration name' nameKind bs <$> f' val) <*> desugarTypeDeclarations rest where
src/Language/PureScript/TypeChecker.hs view
@@ -10,6 +10,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Monad (when, unless, void, forM) import Control.Monad.Error.Class (MonadError(..))@@ -19,7 +20,7 @@ import Control.Lens ((^..), _1, _2) import Data.Foldable (for_, traverse_, toList)-import Data.List (nub, nubBy, (\\), sort, group)+import Data.List (nubBy, (\\), sort, group) import Data.Maybe import qualified Data.Map as M import qualified Data.Set as S@@ -113,7 +114,8 @@ putEnv (env { names = M.insert (Qualified (Just moduleName) name) (ty, nameKind, Defined) (names env) }) addTypeClass- :: (MonadState CheckState m)+ :: forall m+ . (MonadState CheckState m, MonadError MultipleErrors m) => ModuleName -> ProperName 'ClassName -> [(Text, Maybe Kind)]@@ -121,16 +123,37 @@ -> [FunctionalDependency] -> [Declaration] -> m ()-addTypeClass moduleName pn args implies dependencies ds =- modify $ \st -> st { checkEnv = (checkEnv st) { typeClasses = M.insert (Qualified (Just moduleName) pn) newClass (typeClasses . checkEnv $ st) } }+addTypeClass moduleName pn args implies dependencies ds = do+ env <- getEnv+ traverse_ (checkMemberIsUsable (typeSynonyms env)) classMembers+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClasses = M.insert (Qualified (Just moduleName) pn) newClass (typeClasses . checkEnv $ st) } } where+ classMembers :: [(Ident, Type)]+ classMembers = map toPair ds+ newClass :: TypeClassData- newClass = makeTypeClassData args (map toPair ds) implies dependencies+ newClass = makeTypeClassData args classMembers implies dependencies + coveringSets :: [S.Set Int]+ coveringSets = S.toList (typeClassCoveringSets newClass)++ argToIndex :: Text -> Maybe Int+ argToIndex = flip M.lookup $ M.fromList (zipWith ((,) . fst) args [0..])+ toPair (TypeDeclaration ident ty) = (ident, ty) toPair (PositionedDeclaration _ _ d) = toPair d toPair _ = internalError "Invalid declaration in TypeClassDeclaration" + -- Currently we are only checking usability based on the type class currently+ -- being defined. If the mentioned arguments don't include a covering set,+ -- then we won't be able to find a instance.+ checkMemberIsUsable :: T.SynonymMap -> (Ident, Type) -> m ()+ checkMemberIsUsable syns (ident, memberTy) = do+ memberTy' <- T.replaceAllTypeSynonymsM syns memberTy+ let mentionedArgIndexes = S.fromList (mapMaybe argToIndex (freeTypeVariables memberTy'))+ unless (any (`S.isSubsetOf` mentionedArgIndexes) coveringSets) $+ throwError . errorMessage $ UnusableDeclaration ident+ addTypeClassDictionaries :: (MonadState CheckState m) => Maybe ModuleName@@ -148,7 +171,7 @@ throwError . errorMessage $ DuplicateTypeArgument dup where firstDup :: Maybe Text- firstDup = listToMaybe $ args \\ nub args+ firstDup = listToMaybe $ args \\ ordNub args checkTypeClassInstance :: (MonadState CheckState m, MonadError MultipleErrors m)@@ -217,7 +240,7 @@ go (d@(DataBindingGroupDeclaration tys)) = do let syns = mapMaybe toTypeSynonym tys dataDecls = mapMaybe toDataDecl tys- bindingGroupNames = nub ((syns^..traverse._1) ++ (dataDecls^..traverse._2))+ bindingGroupNames = ordNub ((syns^..traverse._1) ++ (dataDecls^..traverse._2)) warnAndRethrow (addHint (ErrorInDataBindingGroup bindingGroupNames)) $ do (syn_ks, data_ks) <- kindsOfAll moduleName syns (map (\(_, name, args, dctors) -> (name, args, concatMap snd dctors)) dataDecls) for_ (zip dataDecls data_ks) $ \((dtype, name, args, dctors), ctorKind) -> do@@ -246,15 +269,16 @@ return $ TypeSynonymDeclaration name args ty go TypeDeclaration{} = internalError "Type declarations should have been removed before typeCheckAlld"- go (ValueDeclaration name nameKind [] (Right val)) = do+ go (ValueDeclaration name nameKind [] [MkUnguarded val]) = do env <- getEnv warnAndRethrow (addHint (ErrorInValueDeclaration name)) $ do val' <- checkExhaustiveExpr env moduleName val valueIsNotDefined moduleName name [(_, (val'', ty))] <- typesOf NonRecursiveBindingGroup moduleName [(name, val')] addValue moduleName name ty nameKind- return $ ValueDeclaration name nameKind [] $ Right val''+ return $ ValueDeclaration name nameKind [] [MkUnguarded val''] go ValueDeclaration{} = internalError "Binders were not desugared"+ go BoundValueDeclaration{} = internalError "BoundValueDeclaration should be desugared" go (BindingGroupDeclaration vals) = do env <- getEnv warnAndRethrow (addHint (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do@@ -458,11 +482,11 @@ findClasses :: Type -> [DeclarationRef] findClasses = everythingOnTypes (++) go where- go (ConstrainedType cs _) = mapMaybe (fmap TypeClassRef . extractCurrentModuleClass . constraintClass) cs+ go (ConstrainedType c _) = (fmap TypeClassRef . extractCurrentModuleClass . constraintClass) c go _ = []- extractCurrentModuleClass :: Qualified (ProperName 'ClassName) -> Maybe (ProperName 'ClassName)- extractCurrentModuleClass (Qualified (Just mn') name) | mn == mn' = Just name- extractCurrentModuleClass _ = Nothing+ extractCurrentModuleClass :: Qualified (ProperName 'ClassName) -> [ProperName 'ClassName]+ extractCurrentModuleClass (Qualified (Just mn') name) | mn == mn' = [name]+ extractCurrentModuleClass _ = [] checkClassMembersAreExported :: DeclarationRef -> m () checkClassMembersAreExported dr@(TypeClassRef name) = do
src/Language/PureScript/TypeChecker/Entailment.hs view
@@ -12,6 +12,7 @@ ) where import Prelude.Compat+import Protolude (ordNub) import Control.Arrow (second) import Control.Monad.Error.Class (MonadError(..))@@ -21,11 +22,11 @@ import Data.Foldable (for_, fold, toList) import Data.Function (on)-import Data.List (minimumBy, nub)+import Data.Functor (($>))+import Data.List (minimumBy) import Data.Maybe (fromMaybe, maybeToList, mapMaybe) import qualified Data.Map as M import qualified Data.Set as S-import qualified Data.Text as T import Data.Text (Text) import Language.PureScript.AST@@ -53,7 +54,9 @@ -- ^ Computed instance of CompareSymbol | AppendSymbolInstance -- ^ Computed instance of AppendSymbol- deriving (Eq)+ | UnionInstance+ -- ^ Computed instance of RowUnion+ deriving (Show, Eq) -- | Extract the identifier of a named instance namedInstanceIdentifier :: Evidence -> Maybe (Qualified Ident)@@ -119,6 +122,7 @@ -- ^ We couldn't solve this constraint right now, it will be generalized | Deferred -- ^ We couldn't solve this constraint right now, so it has been deferred+ deriving Show -- | Options for the constraint solver data SolverOptions = SolverOptions@@ -160,7 +164,10 @@ forClassName _ C.AppendSymbol [arg0@(TypeLevelString lhs), arg1@(TypeLevelString rhs), _] = let args = [arg0, arg1, TypeLevelString (lhs <> rhs)] in [TypeClassDictionaryInScope AppendSymbolInstance [] C.AppendSymbol args Nothing]- forClassName ctx cn@(Qualified (Just mn) _) tys = concatMap (findDicts ctx cn) (nub (Nothing : Just mn : map Just (mapMaybe ctorModules tys)))+ forClassName _ C.Union [l, r, u]+ | Just (lOut, rOut, uOut, cst) <- unionRows l r u+ = [ TypeClassDictionaryInScope UnionInstance [] C.Union [lOut, rOut, uOut] cst ]+ forClassName ctx cn@(Qualified (Just mn) _) tys = concatMap (findDicts ctx cn) (ordNub (Nothing : Just mn : map Just (mapMaybe ctorModules tys))) forClassName _ _ _ = internalError "forClassName: expected qualified class name" ctorModules :: Type -> Maybe ModuleName@@ -221,7 +228,7 @@ -- Solve any necessary subgoals args <- solveSubgoals subst'' (tcdDependencies tcd) initDict <- lift . lift $ mkDictionary (tcdValue tcd) args- let match = foldr (\(superclassName, index) dict -> subclassDictionaryValue dict superclassName index)+ let match = foldr (\(className, index) dict -> subclassDictionaryValue dict className index) initDict (tcdPath tcd) return match@@ -315,11 +322,18 @@ -- Make a dictionary from subgoal dictionaries by applying the correct function mkDictionary :: Evidence -> Maybe [Expr] -> m Expr mkDictionary (NamedInstance n) args = return $ foldl App (Var n) (fold args)+ mkDictionary UnionInstance (Just [e]) =+ -- We need the subgoal dictionary to appear in the term somewhere+ return $ App (Abs (VarBinder (Ident C.__unused)) valUndefined) e+ mkDictionary UnionInstance _ = return valUndefined mkDictionary (WarnInstance msg) _ = do tell . errorMessage $ UserDefinedWarning msg- return $ TypeClassDictionaryConstructorApp C.Warn (Literal (ObjectLiteral []))+ -- We cannot call the type class constructor here because Warn is declared in Prim.+ -- This means that it doesn't have a definition that we can import.+ -- So pass an empty placeholder (undefined) instead.+ return valUndefined mkDictionary (IsSymbolInstance sym) _ =- let fields = [ ("reflectSymbol", Abs (Left (Ident C.__unused)) (Literal (StringLiteral sym))) ] in+ let fields = [ ("reflectSymbol", Abs (VarBinder (Ident C.__unused)) (Literal (StringLiteral sym))) ] in return $ TypeClassDictionaryConstructorApp C.IsSymbol (Literal (ObjectLiteral fields)) mkDictionary CompareSymbolInstance _ = return $ TypeClassDictionaryConstructorApp C.CompareSymbol (Literal (ObjectLiteral []))@@ -327,12 +341,32 @@ return $ TypeClassDictionaryConstructorApp C.AppendSymbol (Literal (ObjectLiteral [])) -- Turn a DictionaryValue into a Expr- subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr- subclassDictionaryValue dict superclassName index =- App (Accessor (mkString (C.__superclass_ <> showQualified runProperName superclassName <> "_" <> T.pack (show index)))- dict)- valUndefined+ subclassDictionaryValue :: Expr -> Qualified (ProperName 'ClassName) -> Integer -> Expr+ subclassDictionaryValue dict className index =+ App (Accessor (mkString (superclassName className index)) dict) valUndefined + -- | Left biased union of two row types+ unionRows :: Type -> Type -> Type -> Maybe (Type, Type, Type, Maybe [Constraint])+ unionRows l r _ =+ guard canMakeProgress $> (l, r, rowFromList out, cons)+ where+ (fixed, rest) = rowToList l++ rowVar = TypeVar "r"++ (canMakeProgress, out, cons) =+ case rest of+ -- If the left hand side is a closed row, then we can merge+ -- its labels into the right hand side.+ REmpty -> (True, (fixed, r), Nothing)+ -- If the left hand side is not definitely closed, then the only way we+ -- can safely make progress is to move any known labels from the left+ -- input into the output, and add a constraint for any remaining labels.+ -- Otherwise, the left hand tail might contain the same labels as on+ -- the right hand side, and we can't be certain we won't reorder the+ -- types for such labels.+ _ -> (not (null fixed), (fixed, rowVar), Just [ Constraint C.Union [rest, r, rowVar] Nothing ])+ -- Check if an instance matches our list of types, allowing for types -- to be solved via functional dependencies. If the types match, we return a -- substitution which makes them match. If not, we return 'Nothing'.@@ -388,24 +422,19 @@ both (typeHeadsAreEqual h1 h2) (typeHeadsAreEqual t1 t2) typeHeadsAreEqual REmpty REmpty = (True, M.empty) typeHeadsAreEqual r1@RCons{} r2@RCons{} =- foldr both (go sd1 r1' sd2 r2') (map (uncurry typeHeadsAreEqual) int)+ foldr both (uncurry go rest) common where- (s1, r1') = rowToList r1- (s2, r2') = rowToList r2-- int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]- sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]- sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]+ (common, rest) = alignRowsWith typeHeadsAreEqual r1 r2 - go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> (Bool, Matching [Type])- go l (KindedType t1 _) r t2 = go l t1 r t2- go l t1 r (KindedType t2 _) = go l t1 r t2- go [] REmpty [] REmpty = (True, M.empty)- go [] (TUnknown u1) [] (TUnknown u2) | u1 == u2 = (True, M.empty)- go [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = (True, M.empty)- go [] (Skolem _ sk1 _ _) [] (Skolem _ sk2 _ _) | sk1 == sk2 = (True, M.empty)- go sd r [] (TypeVar v) = (True, M.singleton v [rowFromList (sd, r)])- go _ _ _ _ = (False, M.empty)+ go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> (Bool, Matching [Type])+ go (l, KindedType t1 _) (r, t2) = go (l, t1) (r, t2)+ go (l, t1) (r, KindedType t2 _) = go (l, t1) (r, t2)+ go ([], REmpty) ([], REmpty) = (True, M.empty)+ go ([], TUnknown u1) ([], TUnknown u2) | u1 == u2 = (True, M.empty)+ go ([], TypeVar v1) ([], TypeVar v2) | v1 == v2 = (True, M.empty)+ go ([], Skolem _ sk1 _ _) ([], Skolem _ sk2 _ _) | sk1 == sk2 = (True, M.empty)+ go (sd, r) ([], TypeVar v) = (True, M.singleton v [rowFromList (sd, r)])+ go _ _ = (False, M.empty) typeHeadsAreEqual _ _ = (False, M.empty) both :: (Bool, Matching [Type]) -> (Bool, Matching [Type]) -> (Bool, Matching [Type])@@ -431,23 +460,18 @@ typesAreEqual (TypeApp h1 t1) (TypeApp h2 t2) = typesAreEqual h1 h2 && typesAreEqual t1 t2 typesAreEqual REmpty REmpty = True typesAreEqual r1 r2 | isRCons r1 || isRCons r2 =- let (s1, r1') = rowToList r1- (s2, r2') = rowToList r2-- int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]- sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]- sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]- in all (uncurry typesAreEqual) int && go sd1 r1' sd2 r2'+ let (common, rest) = alignRowsWith typesAreEqual r1 r2+ in and common && uncurry go rest where- go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> Bool- go l (KindedType t1 _) r t2 = go l t1 r t2- go l t1 r (KindedType t2 _) = go l t1 r t2- go [] (TUnknown u1) [] (TUnknown u2) | u1 == u2 = True- go [] (Skolem _ s1 _ _) [] (Skolem _ s2 _ _) = s1 == s2- go [] REmpty [] REmpty = True- go [] (TypeVar v1) [] (TypeVar v2) = v1 == v2- go _ _ _ _ = False- typesAreEqual _ _ = False+ go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> Bool+ go (l, KindedType t1 _) (r, t2) = go (l, t1) (r, t2)+ go (l, t1) (r, KindedType t2 _) = go (l, t1) (r, t2)+ go ([], TUnknown u1) ([], TUnknown u2) | u1 == u2 = True+ go ([], Skolem _ s1 _ _) ([], Skolem _ s2 _ _) = s1 == s2+ go ([], REmpty) ([], REmpty) = True+ go ([], TypeVar v1) ([], TypeVar v2) = v1 == v2+ go _ _ = False+ typesAreEqual _ _ = False isRCons :: Type -> Bool isRCons RCons{} = True
src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -256,11 +256,10 @@ k2 <- go row unifyKinds k2 (Row k1) return $ Row k1- go (ConstrainedType deps ty) = do- forM_ deps $ \(Constraint className tys _) -> do- k <- go $ foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys- unifyKinds k kindType- k <- go ty- unifyKinds k kindType+ go (ConstrainedType (Constraint className tys _) ty) = do+ k1 <- go $ foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys+ unifyKinds k1 kindType+ k2 <- go ty+ unifyKinds k2 kindType return kindType go ty = internalError $ "Invalid argument to infer: " ++ show ty
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -117,6 +117,11 @@ modify $ \st -> st { checkHints = checkHints orig } return a +-- | These hints are added at the front, so the most nested hint occurs+-- at the front, but the simplifier assumes the reverse order.+getHints :: MonadState CheckState m => m [ErrorMessageHint]+getHints = gets (reverse . checkHints)+ rethrowWithPositionTC :: (MonadState CheckState m, MonadError MultipleErrors m) => SourceSpan
− src/Language/PureScript/TypeChecker/Rows.hs
@@ -1,53 +0,0 @@--- |--- Functions relating to type checking for rows----module Language.PureScript.TypeChecker.Rows- ( checkDuplicateLabels- ) where--import Prelude.Compat--import Control.Monad-import Control.Monad.Error.Class (MonadError(..))--import Data.List--import Language.PureScript.AST-import Language.PureScript.Errors-import Language.PureScript.Types---- | Ensure rows do not contain duplicate labels-checkDuplicateLabels :: forall m. (MonadError MultipleErrors m) => Expr -> m ()-checkDuplicateLabels =- let (_, f, _) = everywhereOnValuesM def go def- in void . f- where- def :: a -> m a- def = return-- go :: Expr -> m Expr- go e@(TypedValue _ val ty) = do- checkDups ty- return e-- where- checkDups :: Type -> m ()- checkDups (TypeApp t1 t2) = checkDups t1 >> checkDups t2- checkDups (ForAll _ t _) = checkDups t- checkDups (ConstrainedType args t) = do- mapM_ checkDups $ concatMap constraintArgs args- checkDups t- checkDups r@RCons{} =- let (ls, _) = rowToList r in- case firstDup . sort . map fst $ ls of- Just l -> throwError . errorMessage $ DuplicateLabel l (Just val)- Nothing -> return ()- checkDups _ = return ()-- firstDup :: (Eq a) => [a] -> Maybe a- firstDup (x : xs@(x' : _))- | x == x' = Just x- | otherwise = firstDup xs- firstDup _ = Nothing-- go other = return other
src/Language/PureScript/TypeChecker/Skolems.hs view
@@ -1,6 +1,4 @@--- |--- Functions relating to skolemization used during typechecking---+-- | Functions relating to skolemization used during typechecking module Language.PureScript.TypeChecker.Skolems ( newSkolemConstant , introduceSkolemScope@@ -14,12 +12,11 @@ import Control.Monad.Error.Class (MonadError(..)) import Control.Monad.State.Class (MonadState(..), gets, modify)-+import Data.Foldable (traverse_) import Data.Functor.Identity (Identity(), runIdentity)-import Data.List (nub, (\\)) import Data.Monoid+import Data.Set (Set, fromList, notMember) import Data.Text (Text)- import Language.PureScript.AST import Language.PureScript.Crash import Language.PureScript.Errors@@ -27,102 +24,107 @@ import Language.PureScript.TypeChecker.Monad import Language.PureScript.Types --- |--- Generate a new skolem constant----newSkolemConstant :: (MonadState CheckState m) => m Int+-- | Generate a new skolem constant+newSkolemConstant :: MonadState CheckState m => m Int newSkolemConstant = do s <- gets checkNextSkolem modify $ \st -> st { checkNextSkolem = s + 1 } return s --- |--- Introduce skolem scope at every occurence of a ForAll----introduceSkolemScope :: (MonadState CheckState m) => Type -> m Type+-- | Introduce skolem scope at every occurence of a ForAll+introduceSkolemScope :: MonadState CheckState m => Type -> m Type introduceSkolemScope = everywhereOnTypesM go where go (ForAll ident ty Nothing) = ForAll ident ty <$> (Just <$> newSkolemScope) go other = return other --- |--- Generate a new skolem scope----newSkolemScope :: (MonadState CheckState m) => m SkolemScope+-- | Generate a new skolem scope+newSkolemScope :: MonadState CheckState m => m SkolemScope newSkolemScope = do s <- gets checkNextSkolemScope modify $ \st -> st { checkNextSkolemScope = s + 1 } return $ SkolemScope s --- |--- Skolemize a type variable by replacing its instances with fresh skolem constants---+-- | Skolemize a type variable by replacing its instances with fresh skolem constants skolemize :: Text -> Int -> SkolemScope -> Maybe SourceSpan -> Type -> Type skolemize ident sko scope ss = replaceTypeVars ident (Skolem ident sko scope ss) --- |--- This function has one purpose - to skolemize type variables appearing in a--- DeferredDictionary placeholder. These type variables are somewhat unique since they are the--- only example of scoped type variables.---+-- | This function skolemizes type variables appearing in any type signatures or+-- 'DeferredDictionary' placeholders. These type variables are the only places+-- where scoped type variables can appear in expressions. skolemizeTypesInValue :: Text -> Int -> SkolemScope -> Maybe SourceSpan -> Expr -> Expr skolemizeTypesInValue ident sko scope ss =- let- (_, f, _, _, _) = everywhereWithContextOnValuesM [] defS onExpr onBinder defS defS- in runIdentity . f+ runIdentity . onExpr' where- onExpr :: [Text] -> Expr -> Identity ([Text], Expr)- onExpr sco (DeferredDictionary c ts)- | ident `notElem` sco = return (sco, DeferredDictionary c (map (skolemize ident sko scope ss) ts))- onExpr sco (TypedValue check val ty)- | ident `notElem` sco = return (sco ++ peelTypeVars ty, TypedValue check val (skolemize ident sko scope ss ty))- onExpr sco other = return (sco, other)+ onExpr' :: Expr -> Identity Expr+ (_, onExpr', _, _, _) = everywhereWithContextOnValuesM [] defS onExpr onBinder defS defS - onBinder :: [Text] -> Binder -> Identity ([Text], Binder)- onBinder sco (TypedBinder ty b)- | ident `notElem` sco = return (sco ++ peelTypeVars ty, TypedBinder (skolemize ident sko scope ss ty) b)- onBinder sco other = return (sco, other)+ onExpr :: [Text] -> Expr -> Identity ([Text], Expr)+ onExpr sco (DeferredDictionary c ts)+ | ident `notElem` sco = return (sco, DeferredDictionary c (map (skolemize ident sko scope ss) ts))+ onExpr sco (TypedValue check val ty)+ | ident `notElem` sco = return (sco ++ peelTypeVars ty, TypedValue check val (skolemize ident sko scope ss ty))+ onExpr sco other = return (sco, other) - peelTypeVars :: Type -> [Text]- peelTypeVars (ForAll i ty _) = i : peelTypeVars ty- peelTypeVars _ = []+ onBinder :: [Text] -> Binder -> Identity ([Text], Binder)+ onBinder sco (TypedBinder ty b)+ | ident `notElem` sco = return (sco ++ peelTypeVars ty, TypedBinder (skolemize ident sko scope ss ty) b)+ onBinder sco other = return (sco, other) --- |--- Ensure skolem variables do not escape their scope+ peelTypeVars :: Type -> [Text]+ peelTypeVars (ForAll i ty _) = i : peelTypeVars ty+ peelTypeVars _ = []++-- | Ensure skolem variables do not escape their scope ---skolemEscapeCheck :: (MonadError MultipleErrors m) => Expr -> m ()+-- Every skolem variable is created when a 'ForAll' type is skolemized.+-- This determines the scope of that skolem variable, which is copied from+-- the 'SkolemScope' field of the 'ForAll' constructor.+--+-- This function traverses the tree top-down, and collects any 'SkolemScope's+-- introduced by 'ForAll's. If a 'Skolem' is encountered whose 'SkolemScope' is+-- not in the current list, then we have found an escaped skolem variable.+skolemEscapeCheck :: MonadError MultipleErrors m => Expr -> m () skolemEscapeCheck (TypedValue False _ _) = return ()-skolemEscapeCheck root@TypedValue{} =- -- Every skolem variable is created when a ForAll type is skolemized.- -- This determines the scope of that skolem variable, which is copied from the SkolemScope- -- field of the ForAll constructor.- -- We traverse the tree top-down, and collect any SkolemScopes introduced by ForAlls.- -- If a Skolem is encountered whose SkolemScope is not in the current list, we have found- -- an escaped skolem variable.- let (_, f, _, _, _) = everythingWithContextOnValues [] [] (++) def go def def def- in case f root of- [] -> return ()- ((binding, val) : _) -> throwError . singleError $ ErrorMessage [ ErrorInExpression val ] $ EscapedSkolem binding+skolemEscapeCheck expr@TypedValue{} =+ traverse_ (throwError . singleError) (toSkolemErrors expr) where- def s _ = (s, [])+ toSkolemErrors :: Expr -> [ErrorMessage]+ (_, toSkolemErrors, _, _, _) = everythingWithContextOnValues (mempty, Nothing) [] (<>) def go def def def - go :: [(SkolemScope, Expr)] -> Expr -> ([(SkolemScope, Expr)], [(Maybe Expr, Expr)])- go scos val@(TypedValue _ _ (ForAll _ _ (Just sco))) = ((sco, val) : scos, [])- go scos val@(TypedValue _ _ ty) = case collectSkolems ty \\ map fst scos of- (sco : _) -> (scos, [(findBindingScope sco, val)])- _ -> (scos, [])- where- collectSkolems :: Type -> [SkolemScope]- collectSkolems = nub . everythingOnTypes (++) collect+ def s _ = (s, [])++ go :: (Set SkolemScope, Maybe SourceSpan)+ -> Expr+ -> ((Set SkolemScope, Maybe SourceSpan), [ErrorMessage])+ go (scopes, _) (PositionedValue ss _ _) = ((scopes, Just ss), [])+ go (scopes, ssUsed) val@(TypedValue _ _ ty) =+ ( (allScopes, ssUsed)+ , [ ErrorMessage (maybe id ((:) . PositionedError) ssUsed [ ErrorInExpression val ]) $+ EscapedSkolem name ssBound ty+ | (name, scope, ssBound) <- collectSkolems ty+ , notMember scope allScopes+ ]+ ) where- collect (Skolem _ _ scope _) = [scope]- collect _ = []- go scos _ = (scos, [])- findBindingScope :: SkolemScope -> Maybe Expr- findBindingScope sco =- let (_, f, _, _, _) = everythingOnValues mappend (const mempty) go' (const mempty) (const mempty) (const mempty)- in getFirst $ f root- where- go' val@(TypedValue _ _ (ForAll _ _ (Just sco'))) | sco == sco' = First (Just val)- go' _ = mempty-skolemEscapeCheck _ = internalError "Untyped value passed to skolemEscapeCheck"+ -- Any new skolem scopes introduced by universal quantifiers+ newScopes :: [SkolemScope]+ newScopes = collectScopes ty++ -- All scopes, including new scopes+ allScopes :: Set SkolemScope+ allScopes = fromList newScopes <> scopes++ -- Collect any scopes appearing in quantifiers at the top level+ collectScopes :: Type -> [SkolemScope]+ collectScopes (ForAll _ t (Just sco)) = sco : collectScopes t+ collectScopes ForAll{} = internalError "skolemEscapeCheck: No skolem scope"+ collectScopes _ = []++ -- Collect any skolem variables appearing in a type+ collectSkolems :: Type -> [(Text, SkolemScope, Maybe SourceSpan)]+ collectSkolems = everythingOnTypes (++) collect where+ collect (Skolem name _ scope srcSpan) = [(name, scope, srcSpan)]+ collect _ = []+ go scos _ = (scos, [])+skolemEscapeCheck _ = internalError "skolemEscapeCheck: untyped value"
src/Language/PureScript/TypeChecker/Subsumption.hs view
@@ -10,10 +10,10 @@ import Control.Monad (when) import Control.Monad.Error.Class (MonadError(..))-import Control.Monad.State.Class (MonadState(..), gets)+import Control.Monad.State.Class (MonadState(..)) import Data.Foldable (for_)-import Data.List (sortBy, uncons)+import Data.List (uncons) import Data.List.Ordered (minusBy') import Data.Ord (comparing) @@ -96,18 +96,14 @@ subsumes' mode ty1 ty2 -- Only check subsumption for constrained types when elaborating. -- Otherwise fall back to unification.-subsumes' SElaborate (ConstrainedType constraints ty1) ty2 = do+subsumes' SElaborate (ConstrainedType con ty1) ty2 = do dicts <- getTypeClassDictionaries- hints <- gets checkHints+ hints <- getHints elaborate <- subsumes' SElaborate ty1 ty2- let addDicts val = foldl App val (map (\cs -> TypeClassDictionary cs dicts hints) constraints)+ let addDicts val = App val (TypeClassDictionary con dicts hints) return (elaborate . addDicts) subsumes' mode (TypeApp f1 r1) (TypeApp f2 r2) | f1 == tyRecord && f2 == tyRecord = do- let- (ts1, r1') = rowToList r1- (ts2, r2') = rowToList r2- ts1' = sortBy (comparing fst) ts1- ts2' = sortBy (comparing fst) ts2+ let (common, ((ts1', r1'), (ts2', r2'))) = alignRowsWith (subsumes' SNoElaborate) r1 r2 -- For { ts1 | r1 } to subsume { ts2 | r2 } when r1 is empty (= we're working with a closed row), -- every property in ts2 must appear in ts1. If not, then the candidate expression is missing a required property. -- Conversely, when r2 is empty, every property in ts1 must appear in ts2, or else the expression has@@ -116,25 +112,12 @@ (for_ (firstMissingProp ts2' ts1') (throwError . errorMessage . PropertyIsMissing . fst)) when (r2' == REmpty) (for_ (firstMissingProp ts1' ts2') (throwError . errorMessage . AdditionalProperty . fst))- go ts1' ts2' r1' r2'+ -- Check subsumption for common labels+ sequence_ common+ unifyTypes (rowFromList (ts1', r1')) (rowFromList (ts2', r2')) -- Nothing was elaborated, return the default coercion return (defaultCoercion mode) where- go [] ts2 r1' r2' = unifyTypes r1' (rowFromList (ts2, r2'))- go ts1 [] r1' r2' = unifyTypes r2' (rowFromList (ts1, r1'))- go ((p1, ty1) : ts1) ((p2, ty2) : ts2) r1' r2'- | p1 == p2 = do subsumes' SNoElaborate ty1 ty2- go ts1 ts2 r1' r2'- | p1 < p2 = do rest <- freshType- -- What happens next is a bit of a hack.- -- TODO: in the new type checker, object properties will probably be restricted to being monotypes- -- in which case, this branch of the subsumes function should not even be necessary.- unifyTypes r2' (RCons p1 ty1 rest)- go ts1 ((p2, ty2) : ts2) r1' rest- | otherwise = do rest <- freshType- unifyTypes r1' (RCons p2 ty2 rest)- go ((p1, ty1) : ts1) ts2 rest r2'- -- Find the first property that's in the first list (of tuples) but not in the second firstMissingProp t1 t2 = fst <$> uncons (minusBy' (comparing fst) t1 t2) subsumes' mode ty1 ty2@(TypeApp obj _) | obj == tyRecord =
src/Language/PureScript/TypeChecker/TypeSearch.hs view
@@ -4,7 +4,7 @@ import Protolude -import Control.Monad.Writer+import Control.Monad.Writer (WriterT, runWriterT) import qualified Data.Map as Map import qualified Language.PureScript.TypeChecker.Entailment as Entailment @@ -16,7 +16,9 @@ import Language.PureScript.AST as P import Language.PureScript.Environment as P import Language.PureScript.Errors as P+import Language.PureScript.Label import Language.PureScript.Names as P+import Language.PureScript.Pretty.Types as P import Language.PureScript.TypeChecker.Skolems as Skolem import Language.PureScript.TypeChecker.Synonyms as P import Language.PureScript.Types as P@@ -76,6 +78,32 @@ -- Finally, check any constraints which were found during elaboration Entailment.replaceTypeClassDictionaries (isJust unsolved) expP +accessorSearch+ :: Maybe [(P.Ident, Entailment.InstanceContext, P.Constraint)]+ -> P.Environment+ -> TC.CheckState+ -> P.Type+ -> ([(Label, P.Type)], [(Label, P.Type)])+ -- ^ (all accessors we found, all accessors we found that match the result type)+accessorSearch unsolved env st userT = maybe ([], []) fst $ checkInEnvironment env st $ do+ let initializeSkolems =+ Skolem.introduceSkolemScope+ <=< P.replaceAllTypeSynonyms+ <=< P.replaceTypeWildcards++ userT' <- initializeSkolems userT++ rowType <- freshType+ resultType <- freshType+ let recordFunction = TypeApp (TypeApp tyFunction (TypeApp tyRecord rowType)) resultType+ _ <- subsumes recordFunction userT'+ subst <- gets TC.checkSubstitution+ let solvedRow = fst (rowToList (substituteType subst rowType))+ tcS <- get+ pure (solvedRow, filter (\x -> checkAccessor tcS (substituteType subst resultType) x) solvedRow)+ where+ checkAccessor tcs x (_, type') = isJust (checkSubsume unsolved env tcs x type')+ typeSearch :: Maybe [(P.Ident, Entailment.InstanceContext, P.Constraint)] -- ^ Additional constraints we need to satisfy@@ -85,6 +113,11 @@ -- ^ The typechecker state -> P.Type -- ^ The type we are looking for- -> Map (P.Qualified P.Ident) P.Type+ -> ([(P.Qualified Text, P.Type)], Maybe [(Label, P.Type)]) typeSearch unsolved env st type' =- Map.mapMaybe (\(x, _, _) -> checkSubsume unsolved env st type' x $> x) (P.names env)+ let+ resultMap = Map.mapMaybe (\(x, _, _) -> checkSubsume unsolved env st type' x $> x) (P.names env)+ (allLabels, solvedLabels) = accessorSearch unsolved env st type'+ solvedLabels' = first (P.Qualified Nothing . ("_." <>) . P.prettyPrintLabel) <$> solvedLabels+ in+ (solvedLabels' <> (first (map P.runIdent) <$> Map.toList resultMap), if null allLabels then Nothing else Just allLabels)
src/Language/PureScript/TypeChecker/Types.hs view
@@ -25,6 +25,7 @@ -} import Prelude.Compat+import Protolude (ordNub) import Control.Arrow (first, second, (***)) import Control.Monad@@ -36,7 +37,7 @@ import Data.Bifunctor (bimap) import Data.Either (partitionEithers) import Data.Functor (($>))-import Data.List (transpose, nub, (\\), partition, delete)+import Data.List (transpose, (\\), partition, delete) import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import qualified Data.Map as M@@ -53,7 +54,6 @@ import Language.PureScript.TypeChecker.Entailment import Language.PureScript.TypeChecker.Kinds import Language.PureScript.TypeChecker.Monad-import Language.PureScript.TypeChecker.Rows import Language.PureScript.TypeChecker.Skolems import Language.PureScript.TypeChecker.Subsumption import Language.PureScript.TypeChecker.Synonyms@@ -89,7 +89,7 @@ -- Generalize and constrain the type currentSubst <- gets checkSubstitution let ty' = substituteType currentSubst ty- unsolvedTypeVars = nub $ unknownsInType ty'+ unsolvedTypeVars = ordNub $ unknownsInType ty' generalized = generalize unsolved ty' when shouldGeneralize $ do@@ -110,15 +110,13 @@ let findClass = fromMaybe (internalError "entails: type class not found in environment") . M.lookup (constraintClass con) TypeClassData{ typeClassDependencies } <- gets (findClass . typeClasses . checkEnv) let solved = foldMap (S.fromList . fdDetermined) typeClassDependencies- let constraintTypeVars = nub . foldMap (unknownsInType . fst) . filter ((`notElem` solved) . snd) $ zip (constraintArgs con) [0..]+ let constraintTypeVars = ordNub . foldMap (unknownsInType . fst) . filter ((`notElem` solved) . snd) $ zip (constraintArgs con) [0..] when (any (`notElem` unsolvedTypeVars) constraintTypeVars) $ do throwError . onErrorMessages (replaceTypes currentSubst) . errorMessage $ AmbiguousTypeVariables generalized con -- Check skolem variables did not escape their scope skolemEscapeCheck val'- -- Check rows do not contain duplicate labels- checkDuplicateLabels val'- return ((ident, (foldr (Abs . Left . (\(x, _, _) -> x)) val' unsolved, generalized)), unsolved)+ return ((ident, (foldr (Abs . VarBinder . (\(x, _, _) -> x)) val' unsolved, generalized)), unsolved) -- Show warnings here, since types in wildcards might have been solved during -- instance resolution (by functional dependencies).@@ -150,17 +148,17 @@ runTypeSearch cons st = \case ErrorMessage hints (HoleInferredType x ty y (TSBefore env)) -> let subst = checkSubstitution st- searchResult = (fmap . fmap) (substituteType subst)- (M.toList (typeSearch cons env st (substituteType subst ty)))- in ErrorMessage hints (HoleInferredType x ty y (TSAfter searchResult))+ searchResult = onTypeSearchTypes+ (substituteType subst)+ (uncurry TSAfter (typeSearch cons env st (substituteType subst ty)))+ in ErrorMessage hints (HoleInferredType x ty y searchResult) other -> other -- | Generalize type vars using forall and add inferred constraints generalize unsolved = varIfUnknown . constrain unsolved -- | Add any unsolved constraints- constrain [] = id- constrain cs = ConstrainedType (map (\(_, _, x) -> x) cs)+ constrain cs ty = foldr ConstrainedType ty (map (\(_, _, x) -> x) cs) -- Apply the substitution that was returned from runUnify to both types and (type-annotated) values tidyUp ts sub = first (map (second (first (second (overTypes (substituteType sub) *** substituteType sub))))) ts@@ -241,7 +239,7 @@ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty -- Check the type with the new names in scope val' <- if checkType- then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val ty' <*> pure ty'+ then withScopedTypeVars mn args $ bindNames dict $ check val ty' else return (TypedValue False val ty') return (ident, (val', ty')) @@ -282,10 +280,10 @@ instantiatePolyTypeWithUnknowns val (ForAll ident ty _) = do ty' <- replaceVarWithUnknown ident ty instantiatePolyTypeWithUnknowns val ty'-instantiatePolyTypeWithUnknowns val (ConstrainedType constraints ty) = do+instantiatePolyTypeWithUnknowns val (ConstrainedType con ty) = do dicts <- getTypeClassDictionaries- hints <- gets checkHints- instantiatePolyTypeWithUnknowns (foldl App val (map (\cs -> TypeClassDictionary cs dicts hints) constraints)) ty+ hints <- getHints+ instantiatePolyTypeWithUnknowns (App val (TypeClassDictionary con dicts hints)) ty instantiatePolyTypeWithUnknowns val ty = return (val, ty) -- | Infer a type for a value, rethrowing any error to provide a more useful error message@@ -297,7 +295,8 @@ -- | Infer a type for a value infer'- :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)+ :: forall m+ . (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) => Expr -> m Expr infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt@@ -315,10 +314,24 @@ return $ TypedValue True (Literal (ArrayLiteral ts')) (TypeApp tyArray els) infer' (Literal (ObjectLiteral ps)) = do ensureNoDuplicateProperties ps- ts <- traverse (infer . snd) ps- let fields = zipWith (\name (TypedValue _ _ t) -> (Label name, t)) (map fst ps) ts- ty = TypeApp tyRecord $ rowFromList (fields, REmpty)- return $ TypedValue True (Literal (ObjectLiteral (zip (map fst ps) ts))) ty+ -- We make a special case for Vars in record labels, since these are the+ -- only types of expressions for which 'infer' can return a polymorphic type.+ -- They need to be instantiated here.+ let shouldInstantiate :: Expr -> Bool+ shouldInstantiate Var{} = True+ shouldInstantiate (PositionedValue _ _ e) = shouldInstantiate e+ shouldInstantiate _ = False++ inferProperty :: (PSString, Expr) -> m (PSString, (Expr, Type))+ inferProperty (name, val) = do+ TypedValue _ val' ty <- infer val+ valAndType <- if shouldInstantiate val+ then instantiatePolyTypeWithUnknowns val' ty+ else pure (val', ty)+ pure (name, valAndType)+ fields <- forM ps inferProperty+ let ty = TypeApp tyRecord $ rowFromList (map (Label *** snd) fields, REmpty)+ return $ TypedValue True (Literal (ObjectLiteral (map (fmap (uncurry (TypedValue True))) fields))) ty infer' (ObjectUpdate o ps) = do ensureNoDuplicateProperties ps row <- freshType@@ -333,12 +346,13 @@ rest <- freshType typed <- check val (TypeApp tyRecord (RCons (Label prop) field rest)) return $ TypedValue True (Accessor prop typed) field-infer' (Abs (Left arg) ret) = do- ty <- freshType- withBindingGroupVisible $ bindLocalVariables [(arg, ty, Defined)] $ do- body@(TypedValue _ _ bodyTy) <- infer' ret- return $ TypedValue True (Abs (Left arg) body) $ function ty bodyTy-infer' (Abs (Right _) _) = internalError "Binder was not desugared"+infer' (Abs binder ret)+ | VarBinder arg <- binder = do+ ty <- freshType+ withBindingGroupVisible $ bindLocalVariables [(arg, ty, Defined)] $ do+ body@(TypedValue _ _ bodyTy) <- infer' ret+ return $ TypedValue True (Abs (VarBinder arg) body) $ function ty bodyTy+ | otherwise = internalError "Binder was not desugared" infer' (App f arg) = do f'@(TypedValue _ _ ft) <- infer f (ret, app) <- checkFunctionApplication f' ft arg@@ -347,10 +361,10 @@ checkVisibility var ty <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards <=< lookupVariable $ var case ty of- ConstrainedType constraints ty' -> do+ ConstrainedType con ty' -> do dicts <- getTypeClassDictionaries- hints <- gets checkHints- return $ TypedValue True (foldl App (Var var) (map (\cs -> TypeClassDictionary cs dicts hints) constraints)) ty'+ hints <- getHints+ return $ TypedValue True (App (Var var) (TypeClassDictionary con dicts hints)) ty' _ -> return $ TypedValue True (Var var) ty infer' v@(Constructor c) = do env <- getEnv@@ -376,8 +390,10 @@ return $ TypedValue True (Let ds' val') valTy infer' (DeferredDictionary className tys) = do dicts <- getTypeClassDictionaries- hints <- gets checkHints- return $ TypeClassDictionary (Constraint className tys Nothing) dicts hints+ hints <- getHints+ return $ TypedValue False+ (TypeClassDictionary (Constraint className tys Nothing) dicts hints)+ (foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys) infer' (TypedValue checkType val ty) = do Just moduleName <- checkCurrentModule <$> get (kind, args) <- kindOfWithScopedVars ty@@ -404,20 +420,20 @@ -> (Expr -> m Expr) -> m ([Declaration], Expr) inferLetBinding seen [] ret j = (,) seen <$> withBindingGroupVisible (j ret)-inferLetBinding seen (ValueDeclaration ident nameKind [] (Right (tv@(TypedValue checkType val ty))) : rest) ret j = do+inferLetBinding seen (ValueDeclaration ident nameKind [] [MkUnguarded tv@(TypedValue checkType val ty)] : rest) ret j = do Just moduleName <- checkCurrentModule <$> get (kind, args) <- kindOfWithScopedVars ty checkTypeKind ty kind let dict = M.singleton (Qualified Nothing ident) (ty, nameKind, Undefined) ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty TypedValue _ val' ty'' <- if checkType then withScopedTypeVars moduleName args (bindNames dict (check val ty')) else return tv- bindNames (M.singleton (Qualified Nothing ident) (ty'', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] (Right (TypedValue checkType val' ty''))]) rest ret j-inferLetBinding seen (ValueDeclaration ident nameKind [] (Right val) : rest) ret j = do+ bindNames (M.singleton (Qualified Nothing ident) (ty'', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] [MkUnguarded (TypedValue checkType val' ty'')]]) rest ret j+inferLetBinding seen (ValueDeclaration ident nameKind [] [MkUnguarded val] : rest) ret j = do valTy <- freshType let dict = M.singleton (Qualified Nothing ident) (valTy, nameKind, Undefined) TypedValue _ val' valTy' <- bindNames dict $ infer val unifyTypes valTy valTy'- bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] (Right val')]) rest ret j+ bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] [MkUnguarded val']]) rest ret j inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do Just moduleName <- checkCurrentModule <$> get SplitBindingGroup untyped typed dict <- typeDictionaryForBindingGroup Nothing (map (\(i, _, v) -> (i, v)) ds)@@ -537,23 +553,33 @@ checkBinders _ _ [] = return [] checkBinders nvals ret (CaseAlternative binders result : bs) = do guardWith (errorMessage $ OverlappingArgNames Nothing) $- let ns = concatMap binderNames binders in length (nub ns) == length ns+ let ns = concatMap binderNames binders in length (ordNub ns) == length ns m1 <- M.unions <$> zipWithM inferBinder nvals binders r <- bindLocalVariables [ (name, ty, Defined) | (name, ty) <- M.toList m1 ] $ CaseAlternative binders <$> case result of- Left gs -> do- gs' <- forM gs $ \(grd, val) -> do- grd' <- withErrorMessageHint ErrorCheckingGuard $ check grd tyBoolean- val' <- TypedValue True <$> check val ret <*> pure ret- return (grd', val')- return $ Left gs'- Right val -> do+ [MkUnguarded val] -> do val' <- TypedValue True <$> check val ret <*> pure ret- return $ Right val'+ return [MkUnguarded val']+ gs -> forM gs (\ge -> checkGuardedRhs ge ret) rs <- checkBinders nvals ret bs return $ r : rs +checkGuardedRhs+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)+ => GuardedExpr+ -> Type+ -> m GuardedExpr+checkGuardedRhs (GuardedExpr [] rhs) ret = do+ rhs' <- TypedValue True <$> check rhs ret <*> pure ret+ return $ GuardedExpr [] rhs'+checkGuardedRhs (GuardedExpr [ConditionGuard cond] rhs) ret = do+ cond' <- withErrorMessageHint ErrorCheckingGuard $ check cond tyBoolean+ rhs' <- TypedValue True <$> check rhs ret <*> pure ret+ return $ GuardedExpr [ConditionGuard cond'] rhs'+checkGuardedRhs _ _ =+ internalError "Pattern not desugared"+ -- | -- Check the type of a value, rethrowing errors to provide a better error message --@@ -583,12 +609,11 @@ skVal = skolemizeTypesInValue ident sko scope ss val val' <- check skVal sk return $ TypedValue True val' (ForAll ident ty (Just scope))-check' val t@(ConstrainedType constraints ty) = do- dictNames <- forM constraints $ \(Constraint (Qualified _ (ProperName className)) _ _) ->- freshIdent ("dict" <> className)- dicts <- join <$> zipWithM (newDictionaries []) (map (Qualified Nothing) dictNames) constraints+check' val t@(ConstrainedType con@(Constraint (Qualified _ (ProperName className)) _ _) ty) = do+ dictName <- freshIdent ("dict" <> className)+ dicts <- newDictionaries [] (Qualified Nothing dictName) con val' <- withBindingGroupVisible $ withTypeClassDictionaries dicts $ check val ty- return $ TypedValue True (foldr (Abs . Left) val' dictNames) t+ return $ TypedValue True (Abs (VarBinder dictName) val') t check' val u@(TUnknown _) = do val'@(TypedValue _ _ ty) <- infer val -- Don't unify an unknown with an inferred polytype@@ -609,11 +634,12 @@ unifyTypes a tyArray array <- Literal . ArrayLiteral <$> forM vals (`check` ty) return $ TypedValue True array t-check' (Abs (Left arg) ret) ty@(TypeApp (TypeApp t argTy) retTy) = do- unifyTypes t tyFunction- ret' <- withBindingGroupVisible $ bindLocalVariables [(arg, argTy, Defined)] $ check ret retTy- return $ TypedValue True (Abs (Left arg) ret') ty-check' (Abs (Right _) _) _ = internalError "Binder was not desugared"+check' (Abs binder ret) ty@(TypeApp (TypeApp t argTy) retTy)+ | VarBinder arg <- binder = do+ unifyTypes t tyFunction+ ret' <- withBindingGroupVisible $ bindLocalVariables [(arg, argTy, Defined)] $ check ret retTy+ return $ TypedValue True (Abs (VarBinder arg) ret') ty+ | otherwise = internalError "Binder was not desugared" check' (App f arg) ret = do f'@(TypedValue _ _ ft) <- infer f (retTy, app) <- checkFunctionApplication f' ft arg@@ -625,7 +651,7 @@ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty elaborate <- subsumes repl ty' return $ TypedValue True (elaborate v) ty'-check' (DeferredDictionary className tys) _ = do+check' (DeferredDictionary className tys) ty = do {- -- Here, we replace a placeholder for a superclass dictionary with a regular -- TypeClassDictionary placeholder. The reason we do this is that it is necessary to have the@@ -633,19 +659,20 @@ -- declaration gets desugared. -} dicts <- getTypeClassDictionaries- hints <- gets checkHints- return $ TypeClassDictionary (Constraint className tys Nothing) dicts hints+ hints <- getHints+ return $ TypedValue False+ (TypeClassDictionary (Constraint className tys Nothing) dicts hints)+ ty check' (TypedValue checkType val ty1) ty2 = do- Just moduleName <- checkCurrentModule <$> get- (kind, args) <- kindOfWithScopedVars ty1+ kind <- kindOf ty1 checkTypeKind ty1 kind ty1' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty1 ty2' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty2- _ <- subsumes ty1' ty2'+ elaborate <- subsumes ty1' ty2' val' <- if checkType- then withScopedTypeVars moduleName args (check val ty2')- else return val- return $ TypedValue checkType val' ty2'+ then check val ty1'+ else pure val+ return $ TypedValue True (TypedValue checkType (elaborate val') ty1') ty2' check' (Case vals binders) ret = do (vals', ts) <- instantiateForBinders vals binders binders' <- checkBinders ts ret binders@@ -682,8 +709,9 @@ Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c Just (_, _, ty1, _) -> do repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1- elaborate <- subsumes repl ty- return $ TypedValue True (elaborate v) ty+ ty' <- introduceSkolemScope ty+ elaborate <- subsumes repl ty'+ return $ TypedValue True (elaborate v) ty' check' (Let ds val) ty = do (ds', val') <- inferLetBinding [] ds val (`check` ty) return $ TypedValue True (Let ds' val') ty@@ -778,10 +806,10 @@ checkFunctionApplication fn replaced arg checkFunctionApplication' fn (KindedType ty _) arg = checkFunctionApplication fn ty arg-checkFunctionApplication' fn (ConstrainedType constraints fnTy) arg = do+checkFunctionApplication' fn (ConstrainedType con fnTy) arg = do dicts <- getTypeClassDictionaries- hints <- gets checkHints- checkFunctionApplication' (foldl App fn (map (\cs -> TypeClassDictionary cs dicts hints) constraints)) fnTy arg+ hints <- getHints+ checkFunctionApplication' (App fn (TypeClassDictionary con dicts hints)) fnTy arg checkFunctionApplication' fn fnTy dict@TypeClassDictionary{} = return (fnTy, App fn dict) checkFunctionApplication' fn u arg = do@@ -800,6 +828,6 @@ ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(PSString, Expr)] -> m () ensureNoDuplicateProperties ps = let ls = map fst ps in- case ls \\ nub ls of+ case ls \\ ordNub ls of l : _ -> throwError . errorMessage $ DuplicateLabel (Label l) Nothing _ -> return ()
src/Language/PureScript/TypeChecker/Unify.hs view
@@ -10,19 +10,22 @@ , unknownsInType , unifyTypes , unifyRows+ , alignRowsWith , replaceVarWithUnknown , replaceTypeWildcards , varIfUnknown ) where import Prelude.Compat+import Protolude (ordNub) +import Control.Arrow (first, second) import Control.Monad import Control.Monad.Error.Class (MonadError(..)) import Control.Monad.State.Class (MonadState(..), gets, modify) import Control.Monad.Writer.Class (MonadWriter(..)) -import Data.List (nub, sort)+import Data.List (sort) import qualified Data.Map as M import Data.Text (Text) import qualified Data.Text as T@@ -115,44 +118,56 @@ unifyTypes' r1 r2@RCons{} = unifyRows r1 r2 unifyTypes' r1@REmpty r2 = unifyRows r1 r2 unifyTypes' r1 r2@REmpty = unifyRows r1 r2- unifyTypes' ty1@(ConstrainedType _ _) ty2 =+ unifyTypes' ty1@ConstrainedType{} ty2 = throwError . errorMessage $ ConstrainedTypeUnified ty1 ty2- unifyTypes' t3 t4@(ConstrainedType _ _) = unifyTypes' t4 t3+ unifyTypes' t3 t4@ConstrainedType{} = unifyTypes' t4 t3 unifyTypes' t3 t4 = throwError . errorMessage $ TypesDoNotUnify t3 t4 --- |--- Unify two rows, updating the current substitution+-- | Align two rows of types, splitting them into three parts: ----- Common labels are first identified, and unified. Remaining labels and types are unified with a--- trailing row unification variable, if appropriate, otherwise leftover labels result in a unification--- error.+-- * 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 -> Type -> a)+ -> Type+ -> Type+ -> ([a], (([(Label, Type)], Type), ([(Label, Type)], Type)))+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@((l1, t1) : r1) rhs@((l2, t2) : r2)+ | l1 < l2 = (second . first . first) ((l1, t1) :) (go r1 rhs)+ | l2 < l1 = (second . second . first) ((l2, t2) :) (go lhs r2)+ | otherwise = first (f t1 t2 :) (go r1 r2)++-- | Unify two rows, updating the current substitution+--+-- Common labels are identified and unified. Remaining labels and types are unified with a+-- trailing row unification variable, if appropriate. unifyRows :: forall m. (MonadError MultipleErrors m, MonadState CheckState m) => Type -> Type -> m ()-unifyRows r1 r2 =- let- (s1, r1') = rowToList r1- (s2, r2') = rowToList r2- int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]- sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]- sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]- in do- forM_ int (uncurry unifyTypes)- unifyRows' sd1 r1' sd2 r2'- where- unifyRows' :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> m ()- unifyRows' [] (TUnknown u) sd r = solveType u (rowFromList (sd, r))- unifyRows' sd r [] (TUnknown u) = solveType u (rowFromList (sd, r))- unifyRows' sd1 (TUnknown u1) sd2 (TUnknown u2) = do+unifyRows r1 r2 = sequence_ matches *> uncurry unifyTails rest where+ (matches, rest) = alignRowsWith unifyTypes r1 r2++ unifyTails :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> m ()+ unifyTails ([], TUnknown u) (sd, r) = solveType u (rowFromList (sd, r))+ unifyTails (sd, r) ([], TUnknown u) = solveType u (rowFromList (sd, r))+ unifyTails ([], REmpty) ([], REmpty) = return ()+ unifyTails ([], TypeVar v1) ([], TypeVar v2) | v1 == v2 = return ()+ unifyTails ([], Skolem _ s1 _ _) ([], Skolem _ s2 _ _) | s1 == s2 = return ()+ unifyTails (sd1, TUnknown u1) (sd2, TUnknown u2) = do forM_ sd1 $ \(_, t) -> occursCheck u2 t forM_ sd2 $ \(_, t) -> occursCheck u1 t- rest <- freshType- solveType u1 (rowFromList (sd2, rest))- solveType u2 (rowFromList (sd1, rest))- unifyRows' [] REmpty [] REmpty = return ()- unifyRows' [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = return ()- unifyRows' [] (Skolem _ s1 _ _) [] (Skolem _ s2 _ _) | s1 == s2 = return ()- unifyRows' _ _ _ _ =+ rest' <- freshType+ solveType u1 (rowFromList (sd2, rest'))+ solveType u2 (rowFromList (sd1, rest'))+ unifyTails _ _ = throwError . errorMessage $ TypesDoNotUnify r1 r2 -- |@@ -181,7 +196,7 @@ -- varIfUnknown :: Type -> Type varIfUnknown ty =- let unks = nub $ unknownsInType ty+ let unks = ordNub $ unknownsInType ty toName = T.cons 't' . T.pack . show ty' = everywhereOnTypes typeToVar ty typeToVar :: Type -> Type
src/Language/PureScript/TypeClassDictionaries.hs view
@@ -4,6 +4,9 @@ import Prelude.Compat +import Data.Monoid ((<>))+import Data.Text (Text, pack)+ import Language.PureScript.Names import Language.PureScript.Types @@ -27,3 +30,7 @@ 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
@@ -7,11 +7,14 @@ module Language.PureScript.Types where import Prelude.Compat+import Protolude (ordNub) +import Control.Arrow (first) import Control.Monad ((<=<)) import qualified Data.Aeson as A import qualified Data.Aeson.TH as A-import Data.List (nub)+import Data.List (sortBy)+import Data.Ord (comparing) import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import Data.Text (Text)@@ -51,7 +54,7 @@ -- | Forall quantifier | ForAll Text Type (Maybe SkolemScope) -- | A type with a set of type class constraints- | ConstrainedType [Constraint] Type+ | ConstrainedType Constraint Type -- | A skolem constant | Skolem Text Int SkolemScope (Maybe SourceSpan) -- | An empty row@@ -83,7 +86,7 @@ -- ^ 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 'String' here because using 'Binder' would introduce a cyclic+ -- Note: we use 'Text' here because using 'Binder' would introduce a cyclic -- dependency in the module graph. deriving (Show, Eq, Ord) @@ -107,49 +110,39 @@ $(A.deriveJSON A.defaultOptions ''Constraint) $(A.deriveJSON A.defaultOptions ''ConstraintData) --- |--- Convert a row to a list of pairs of labels and types---+-- | Convert a row to a list of pairs of labels and types rowToList :: Type -> ([(Label, Type)], Type)-rowToList (RCons name ty row) = let (tys, rest) = rowToList row- in ((name, ty):tys, rest)-rowToList r = ([], r)+rowToList = go where+ go (RCons name ty row) =+ first ((name, ty) :) (rowToList row)+ go r = ([], r) --- |--- Convert a list of labels and types to a row---+-- | Convert a row to a list of pairs of labels and types, sorted by the labels.+rowToSortedList :: Type -> ([(Label, Type)], Type)+rowToSortedList = first (sortBy (comparing fst)) . rowToList++-- | Convert a list of labels and types to a row rowFromList :: ([(Label, Type)], Type) -> Type-rowFromList ([], r) = r-rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))+rowFromList (xs, r) = foldr (uncurry RCons) r xs --- |--- Check whether a type is a monotype---+-- | Check whether a type is a monotype isMonoType :: Type -> Bool isMonoType ForAll{} = False isMonoType (ParensInType t) = isMonoType t isMonoType (KindedType t _) = isMonoType t isMonoType _ = True --- |--- Universally quantify a type---+-- | Universally quantify a type mkForAll :: [Text] -> Type -> Type mkForAll args ty = foldl (\t arg -> ForAll arg t Nothing) ty args --- |--- Replace a type variable, taking into account variable shadowing---+-- | Replace a type variable, taking into account variable shadowing replaceTypeVars :: Text -> Type -> Type -> Type replaceTypeVars v r = replaceAllTypeVars [(v, r)] --- |--- Replace named type variables with types---+-- | Replace named type variables with types replaceAllTypeVars :: [(Text, Type)] -> Type -> Type-replaceAllTypeVars = go []- where-+replaceAllTypeVars = go [] where go :: [Text] -> [(Text, Type)] -> Type -> Type go _ m (TypeVar v) = fromMaybe (TypeVar v) (v `lookup` m) go bs m (TypeApp t1 t2) = TypeApp (go bs m t1) (go bs m t2)@@ -160,89 +153,63 @@ in ForAll v' (go (v' : bs) m t') sco | otherwise = ForAll v (go (v : bs) m t) sco where- keys = map fst m- usedVars = concatMap (usedTypeVariables . snd) m- go bs m (ConstrainedType cs t) = ConstrainedType (map (mapConstraintArgs (map (go bs m))) cs) (go bs m t)+ keys = map fst m+ usedVars = concatMap (usedTypeVariables . snd) m+ go bs m (ConstrainedType c t) = ConstrainedType (mapConstraintArgs (map (go bs m)) c) (go bs m t) go bs m (RCons name' t r) = RCons name' (go bs m t) (go bs m r) go bs m (KindedType t k) = KindedType (go bs m t) k go bs m (BinaryNoParensType t1 t2 t3) = BinaryNoParensType (go bs m t1) (go bs m t2) (go bs m t3) go bs m (ParensInType t) = ParensInType (go bs m t) go _ _ ty = ty - genName orig inUse = try' 0- where+ 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---+-- | Collect all type variables appearing in a type usedTypeVariables :: Type -> [Text]-usedTypeVariables = nub . everythingOnTypes (++) go- where+usedTypeVariables = ordNub . everythingOnTypes (++) go where go (TypeVar v) = [v] go _ = [] --- |--- Collect all free type variables appearing in a type---+-- | Collect all free type variables appearing in a type freeTypeVariables :: Type -> [Text]-freeTypeVariables = nub . go []- where+freeTypeVariables = ordNub . go [] where go :: [Text] -> Type -> [Text] go bound (TypeVar v) | v `notElem` bound = [v] go bound (TypeApp t1 t2) = go bound t1 ++ go bound t2 go bound (ForAll v t _) = go (v : bound) t- go bound (ConstrainedType cs t) = concatMap (concatMap (go bound) . constraintArgs) cs ++ go bound t+ go bound (ConstrainedType c t) = concatMap (go bound) (constraintArgs c) ++ go bound t go bound (RCons _ t r) = go bound t ++ go bound r go bound (KindedType t _) = go bound t go bound (BinaryNoParensType t1 t2 t3) = go bound t1 ++ go bound t2 ++ go bound t3 go bound (ParensInType t) = go bound t go _ _ = [] --- |--- Universally quantify over all type variables appearing free in a type---+-- | Universally quantify over all type variables appearing free in a type quantify :: Type -> Type quantify ty = foldr (\arg t -> ForAll arg t Nothing) ty $ freeTypeVariables ty --- |--- Move all universal quantifiers to the front of a type---+-- | Move all universal quantifiers to the front of a type moveQuantifiersToFront :: Type -> Type-moveQuantifiersToFront = go [] []- where+moveQuantifiersToFront = go [] [] where go qs cs (ForAll q ty sco) = go ((q, sco) : qs) cs ty- go qs cs (ConstrainedType cs' ty) = go qs (cs ++ cs') ty- go qs cs ty =- let constrained = case cs of- [] -> ty- cs' -> ConstrainedType cs' ty- in case qs of- [] -> constrained- qs' -> foldl (\ty' (q, sco) -> ForAll q ty' sco) constrained qs'+ go qs cs (ConstrainedType c ty) = go qs (c : cs) ty+ go qs cs ty = foldl (\ty' (q, sco) -> ForAll q ty' sco) (foldl (flip ConstrainedType) ty cs) qs --- |--- Check if a type contains wildcards---+-- | Check if a type contains wildcards containsWildcards :: Type -> Bool-containsWildcards = everythingOnTypes (||) go- where+containsWildcards = everythingOnTypes (||) go where go :: Type -> Bool go TypeWildcard{} = True go _ = False ------ Traversals---- everywhereOnTypes :: (Type -> Type) -> Type -> Type-everywhereOnTypes f = go- where+everywhereOnTypes f = go where go (TypeApp t1 t2) = f (TypeApp (go t1) (go t2)) go (ForAll arg ty sco) = f (ForAll arg (go ty) sco)- go (ConstrainedType cs ty) = f (ConstrainedType (map (mapConstraintArgs (map go)) cs) (go ty))+ go (ConstrainedType c ty) = f (ConstrainedType (mapConstraintArgs (map go) c) (go ty)) go (RCons name ty rest) = f (RCons name (go ty) (go rest)) go (KindedType ty k) = f (KindedType (go ty) k) go (PrettyPrintFunction t1 t2) = f (PrettyPrintFunction (go t1) (go t2))@@ -253,11 +220,10 @@ go other = f other everywhereOnTypesTopDown :: (Type -> Type) -> Type -> Type-everywhereOnTypesTopDown f = go . f- where+everywhereOnTypesTopDown f = go . f where go (TypeApp t1 t2) = TypeApp (go (f t1)) (go (f t2)) go (ForAll arg ty sco) = ForAll arg (go (f ty)) sco- go (ConstrainedType cs ty) = ConstrainedType (map (mapConstraintArgs (map (go . f))) cs) (go (f ty))+ go (ConstrainedType c ty) = ConstrainedType (mapConstraintArgs (map (go . f)) c) (go (f ty)) go (RCons name ty rest) = RCons name (go (f ty)) (go (f rest)) go (KindedType ty k) = KindedType (go (f ty)) k go (PrettyPrintFunction t1 t2) = PrettyPrintFunction (go (f t1)) (go (f t2))@@ -268,11 +234,10 @@ go other = f other everywhereOnTypesM :: Monad m => (Type -> m Type) -> Type -> m Type-everywhereOnTypesM f = go- where+everywhereOnTypesM f = go where go (TypeApp t1 t2) = (TypeApp <$> go t1 <*> go t2) >>= f go (ForAll arg ty sco) = (ForAll arg <$> go ty <*> pure sco) >>= f- go (ConstrainedType cs ty) = (ConstrainedType <$> mapM (overConstraintArgs (mapM go)) cs <*> go ty) >>= f+ go (ConstrainedType c ty) = (ConstrainedType <$> overConstraintArgs (mapM go) c <*> go ty) >>= f go (RCons name ty rest) = (RCons name <$> go ty <*> go rest) >>= f go (KindedType ty k) = (KindedType <$> go ty <*> pure k) >>= f go (PrettyPrintFunction t1 t2) = (PrettyPrintFunction <$> go t1 <*> go t2) >>= f@@ -283,11 +248,10 @@ go other = f other everywhereOnTypesTopDownM :: Monad m => (Type -> m Type) -> Type -> m Type-everywhereOnTypesTopDownM f = go <=< f- where+everywhereOnTypesTopDownM f = go <=< f where go (TypeApp t1 t2) = TypeApp <$> (f t1 >>= go) <*> (f t2 >>= go) go (ForAll arg ty sco) = ForAll arg <$> (f ty >>= go) <*> pure sco- go (ConstrainedType cs ty) = ConstrainedType <$> mapM (overConstraintArgs (mapM (go <=< f))) cs <*> (f ty >>= go)+ go (ConstrainedType c ty) = ConstrainedType <$> overConstraintArgs (mapM (go <=< f)) c <*> (f ty >>= go) go (RCons name ty rest) = RCons name <$> (f ty >>= go) <*> (f rest >>= go) go (KindedType ty k) = KindedType <$> (f ty >>= go) <*> pure k go (PrettyPrintFunction t1 t2) = PrettyPrintFunction <$> (f t1 >>= go) <*> (f t2 >>= go)@@ -298,11 +262,10 @@ go other = f other everythingOnTypes :: (r -> r -> r) -> (Type -> r) -> Type -> r-everythingOnTypes (<+>) f = go- where+everythingOnTypes (<+>) f = go where go t@(TypeApp t1 t2) = f t <+> go t1 <+> go t2 go t@(ForAll _ ty _) = f t <+> go ty- go t@(ConstrainedType cs ty) = foldl (<+>) (f t) (map go $ concatMap constraintArgs cs) <+> go ty+ go t@(ConstrainedType c ty) = foldl (<+>) (f t) (map go (constraintArgs c)) <+> go ty go t@(RCons _ ty rest) = f t <+> go ty <+> go rest go t@(KindedType ty _) = f t <+> go ty go t@(PrettyPrintFunction t1 t2) = f t <+> go t1 <+> go t2@@ -313,12 +276,11 @@ go other = f other everythingWithContextOnTypes :: s -> r -> (r -> r -> r) -> (s -> Type -> (s, r)) -> Type -> r-everythingWithContextOnTypes s0 r0 (<+>) f = go' s0- where+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 (ForAll _ ty _) = go' s ty- go s (ConstrainedType cs ty) = foldl (<+>) r0 (map (go' s) $ concatMap constraintArgs cs) <+> go' s ty+ go s (ConstrainedType c ty) = foldl (<+>) r0 (map (go' s) (constraintArgs c)) <+> go' s ty go s (RCons _ ty rest) = go' s ty <+> go' s rest go s (KindedType ty _) = go' s ty go s (PrettyPrintFunction t1 t2) = go' s t1 <+> go' s t2
stack.yaml view
@@ -5,4 +5,3 @@ - aeson-better-errors-0.9.1.0 - bower-json-1.0.0.1 - optparse-applicative-0.13.0.0-- turtle-1.3.1
tests/Language/PureScript/Ide/ImportsSpec.hs view
@@ -14,6 +14,13 @@ import System.FilePath import Test.Hspec +noImportsFile :: [Text]+noImportsFile =+ [ "module Main where"+ , ""+ , "myFunc x y = x + y"+ ]+ simpleFile :: [Text] simpleFile = [ "module Main where"@@ -22,6 +29,14 @@ , "myFunc x y = x + y" ] +syntaxErrorFile :: [Text]+syntaxErrorFile =+ [ "module Main where"+ , "import Prelude"+ , ""+ , "myFunc ="+ ]+ splitSimpleFile :: (P.ModuleName, [Text], [Import], [Text]) splitSimpleFile = fromRight (sliceImportSection simpleFile) where@@ -49,6 +64,14 @@ describe "determining the importsection" $ do let moduleSkeleton imports = Right (P.moduleNameFromString "Main", take 1 simpleFile, imports, drop 2 simpleFile)+ it "slices a file without imports and adds a newline after the module declaration" $+ shouldBe (sliceImportSection noImportsFile)+ (Right (P.moduleNameFromString "Main", take 1 noImportsFile ++ [""], [], drop 1 noImportsFile))++ it "handles a file with syntax errors just fine" $+ shouldBe (sliceImportSection syntaxErrorFile)+ (Right (P.moduleNameFromString "Main", take 1 syntaxErrorFile, [preludeImport], drop 2 syntaxErrorFile))+ it "finds a simple import" $ shouldBe (sliceImportSection simpleFile) (moduleSkeleton [preludeImport]) @@ -58,6 +81,14 @@ , " cons)" ])) (moduleSkeleton [preludeImport, arrayImport])+ it "allows multiline import statements with hanging parens" $+ shouldBe+ (sliceImportSection (withImports [ "import Data.Array ("+ , " head,"+ , " cons"+ , ")"+ ]))+ (moduleSkeleton [preludeImport, arrayImport]) describe "pretty printing imports" $ do it "pretty prints a simple import" $ shouldBe (prettyPrintImport' preludeImport) "import Prelude"@@ -80,12 +111,20 @@ prettyPrintImportSection (addExplicitImport' (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName i) t wildcard)) mn is) addTypeImport i mn is = prettyPrintImportSection (addExplicitImport' (IdeDeclType (IdeType (P.ProperName i) P.kindType)) mn is)+ it "adds an implicit unqualified import to a file without any imports" $+ shouldBe+ (addImplicitImport' [] (P.moduleNameFromString "Data.Map"))+ ["import Data.Map"] it "adds an implicit unqualified import" $ shouldBe (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map")) [ "import Prelude" , "import Data.Map" ]+ it "adds an explicit unqualified import to a file without any imports" $+ shouldBe+ (addValueImport "head" (P.moduleNameFromString "Data.Array") [])+ ["import Data.Array (head)"] it "adds an explicit unqualified import" $ shouldBe (addValueImport "head" (P.moduleNameFromString "Data.Array") simpleFileImports)
tests/Language/PureScript/Ide/ReexportsSpec.hs view
@@ -18,6 +18,9 @@ d :: IdeDeclaration -> IdeDeclarationAnn d = IdeDeclarationAnn emptyAnn +exportedFrom :: Text -> IdeDeclarationAnn -> IdeDeclarationAnn+exportedFrom mn (IdeDeclarationAnn ann decl) = IdeDeclarationAnn (ann {_annExportedFrom = Just (m mn)}) decl+ valueA, typeA, classA, dtorA1, dtorA2 :: IdeDeclarationAnn valueA = d (IdeDeclValue (IdeValue (P.Ident "valueA") P.REmpty)) typeA = d (IdeDeclType (IdeType(P.ProperName "TypeA") P.kindType))@@ -32,34 +35,34 @@ type Refs = [(P.ModuleName, P.DeclarationRef)] -succTestCases :: [(Text, [IdeDeclarationAnn], Refs, [IdeDeclarationAnn])]+succTestCases :: [(Text, Refs, [IdeDeclarationAnn])] succTestCases =- [ ("resolves a value reexport", [], [(m "A", P.ValueRef (P.Ident "valueA"))], [valueA])+ [ ("resolves a value reexport", [(m "A", P.ValueRef (P.Ident "valueA"))], [exportedFrom "A" valueA]) , ("resolves a type reexport with explicit data constructors"- , [], [(m "A", P.TypeRef (P.ProperName "TypeA") (Just [P.ProperName "DtorA1"]))], [typeA, dtorA1])+ , [(m "A", P.TypeRef (P.ProperName "TypeA") (Just [P.ProperName "DtorA1"]))], [exportedFrom "A" typeA, exportedFrom "A" dtorA1]) , ("resolves a type reexport with implicit data constructors"- , [], [(m "A", P.TypeRef (P.ProperName "TypeA") Nothing)], [typeA, dtorA1, dtorA2])- , ("resolves a class reexport", [], [(m "A", P.TypeClassRef (P.ProperName "ClassA"))], [classA])+ , [(m "A", P.TypeRef (P.ProperName "TypeA") Nothing)], map (exportedFrom "A") [typeA, dtorA1, dtorA2])+ , ("resolves a class reexport", [(m "A", P.TypeClassRef (P.ProperName "ClassA"))], [exportedFrom "A" classA]) ] -failTestCases :: [(Text, [IdeDeclarationAnn], Refs)]+failTestCases :: [(Text, Refs)] failTestCases =- [ ("fails to resolve a non existing value", [], [(m "A", P.ValueRef (P.Ident "valueB"))])- , ("fails to resolve a non existing type reexport" , [], [(m "A", P.TypeRef (P.ProperName "TypeB") Nothing)])- , ("fails to resolve a non existing class reexport", [], [(m "A", P.TypeClassRef (P.ProperName "ClassB"))])+ [ ("fails to resolve a non existing value", [(m "A", P.ValueRef (P.Ident "valueB"))])+ , ("fails to resolve a non existing type reexport" , [(m "A", P.TypeRef (P.ProperName "TypeB") Nothing)])+ , ("fails to resolve a non existing class reexport", [(m "A", P.TypeClassRef (P.ProperName "ClassB"))]) ] spec :: Spec spec = do describe "Successful Reexports" $- for_ succTestCases $ \(desc, initial, refs, result) ->+ for_ succTestCases $ \(desc, refs, result) -> it (toS desc) $ do- let reResult = resolveReexports' env initial refs+ let reResult = resolveReexports' env refs reResolved reResult `shouldBe` result reResult `shouldSatisfy` not . reexportHasFailures describe "Failed Reexports" $- for_ failTestCases $ \(desc, initial, refs) ->+ for_ failTestCases $ \(desc, refs) -> it (toS desc) $ do- let reResult = resolveReexports' env initial refs+ let reResult = resolveReexports' env refs reFailed reResult `shouldBe` refs reResult `shouldSatisfy` reexportHasFailures
tests/Language/PureScript/Ide/SourceFileSpec.hs view
@@ -18,7 +18,7 @@ typeAnnotation1, value1, synonym1, class1, class2, data1, data2, valueFixity, typeFixity, foreign1, foreign2, foreign3, member1 :: P.Declaration typeAnnotation1 = P.TypeDeclaration (P.Ident "value1") P.REmpty-value1 = P.ValueDeclaration (P.Ident "value1") P.Public [] (Left [])+value1 = P.ValueDeclaration (P.Ident "value1") P.Public [] [] synonym1 = P.TypeSynonymDeclaration (P.ProperName "Synonym1") [] P.REmpty class1 = P.TypeClassDeclaration (P.ProperName "Class1") [] [] [] [] class2 = P.TypeClassDeclaration (P.ProperName "Class2") [] [] []
tests/Language/PureScript/Ide/StateSpec.hs view
@@ -67,6 +67,8 @@ mempty -- } ]+ --, efSourceSpan =+ (P.internalModuleSourceSpan "<tests>") -- } moduleMap :: ModuleMap [IdeDeclarationAnn]
tests/Language/PureScript/Ide/Test.hs view
@@ -47,13 +47,13 @@ ann (IdeDeclarationAnn _ d) a = IdeDeclarationAnn a d annLoc :: IdeDeclarationAnn -> P.SourceSpan -> IdeDeclarationAnn-annLoc (IdeDeclarationAnn a d) loc = IdeDeclarationAnn a {annLocation = Just loc} d+annLoc (IdeDeclarationAnn a d) loc = IdeDeclarationAnn a {_annLocation = Just loc} d annExp :: IdeDeclarationAnn -> P.ModuleName -> IdeDeclarationAnn-annExp (IdeDeclarationAnn a d) e = IdeDeclarationAnn a {annExportedFrom = Just e} d+annExp (IdeDeclarationAnn a d) e = IdeDeclarationAnn a {_annExportedFrom = Just e} d annTyp :: IdeDeclarationAnn -> P.Type -> IdeDeclarationAnn-annTyp (IdeDeclarationAnn a d) ta = IdeDeclarationAnn a {annTypeAnnotation = Just ta} d+annTyp (IdeDeclarationAnn a d) ta = IdeDeclarationAnn a {_annTypeAnnotation = Just ta} d ida :: IdeDeclaration -> IdeDeclarationAnn@@ -112,7 +112,7 @@ compileTestProject :: IO Bool compileTestProject = inProject $ do (_, _, _, procHandle) <-- createProcess $ (shell $ "psc \"src/**/*.purs\"")+ createProcess $ (shell $ "purs compile \"src/**/*.purs\"") r <- tryNTimes 10 (getProcessExitCode procHandle) pure (fromMaybe False (isSuccess <$> r))
tests/TestDocs.hs view
@@ -42,7 +42,7 @@ main :: IO () main = pushd "examples/docs" $ do- res <- Publish.preparePackage publishOpts+ res <- Publish.preparePackage "bower.json" "resolutions.json" publishOpts case res of Left e -> Publish.printErrorToStdout e >> exitFailure Right pkg@Docs.Package{..} ->@@ -276,12 +276,10 @@ checkConstrained :: P.Type -> Text -> Bool checkConstrained ty tyClass =- -- Note that we don't recurse on ConstrainedType if none of the constraints- -- match; this is by design, as constraints should be moved to the front- -- anyway. case ty of- P.ConstrainedType cs _ | any (matches tyClass) cs ->- True+ P.ConstrainedType c ty'+ | matches tyClass c -> True+ | otherwise -> checkConstrained ty' tyClass P.ForAll _ ty' _ -> checkConstrained ty' tyClass _ ->@@ -385,8 +383,8 @@ , ("ConstrainedArgument", [ TypeSynonymShouldRenderAs (n "ConstrainedArgument") "WithoutArgs" "forall a. (Partial => a) -> a" , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "WithArgs" "forall a. (Foo a => a) -> a"- , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithoutArgs" "forall a. ((Partial, Partial) => a) -> a"- , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithArgs" "forall a b. ((Foo a, Foo b) => a) -> a"+ , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithoutArgs" "forall a. (Partial => Partial => a) -> a"+ , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithArgs" "forall a b. (Foo a => Foo b => a) -> a" ]) , ("TypeOpAliases",
tests/TestPscPublish.hs view
@@ -18,7 +18,9 @@ import TestUtils main :: IO ()-main = testPackage "tests/support/bower_components/purescript-prelude"+main = testPackage+ "tests/support/bower_components/purescript-prelude"+ "../../prelude-resolutions.json" data TestResult = ParseFailed String@@ -47,9 +49,9 @@ -- | Given a directory which contains a package, produce JSON from it, and then -- | attempt to parse it again, and ensure that it doesn't change.-testPackage :: String -> IO ()-testPackage dir = pushd dir $ do- res <- preparePackage testRunOptions+testPackage :: FilePath -> FilePath -> IO ()+testPackage dir resolutionsFile = pushd dir $ do+ res <- preparePackage "bower.json" resolutionsFile testRunOptions case res of Left e -> preparePackageError e Right package -> case roundTrip package of
tests/TestPsci.hs view
@@ -1,32 +1,15 @@ {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-} module TestPsci where import Prelude () import Prelude.Compat -import Control.Monad.Trans.State.Strict (evalStateT) import Control.Monad (when)--import Data.List (sort)-import qualified Data.Text as T- import System.Exit (exitFailure)-import System.Console.Haskeline-import System.FilePath ((</>))-import System.Directory (getCurrentDirectory)-import qualified System.FilePath.Glob as Glob- import Test.HUnit--import qualified Language.PureScript as P--import Language.PureScript.Interactive.Module (loadAllModules)-import Language.PureScript.Interactive.Completion-import Language.PureScript.Interactive.Types--import TestUtils (supportModules)+import TestPsci.CommandTest (commandTests)+import TestPsci.CompletionTest (completionTests) main :: IO () main = do@@ -34,105 +17,6 @@ when (errors + failures > 0) exitFailure allTests :: Test-allTests = completionTests--completionTests :: Test-completionTests =- TestLabel "completionTests"- (TestList (map (TestCase . assertCompletedOk) completionTestData))---- If the cursor is at the right end of the line, with the 1st element of the--- pair as the text in the line, then pressing tab should offer all the--- elements of the list (which is the 2nd element) as completions.-completionTestData :: [(String, [String])]-completionTestData =- -- basic directives- [ (":h", [":help"])- , (":re", [":reset"])- , (":q", [":quit"])- , (":b", [":browse"])-- -- :browse should complete module names- , (":b Control.Monad.E", map (":b Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])- , (":b Control.Monad.Eff.", map (":b Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])-- -- import should complete module names- , ("import Control.Monad.E", map ("import Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])- , ("import Control.Monad.Eff.", map ("import Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])-- -- :quit, :help, :reset should not complete- , (":help ", [])- , (":quit ", [])- , (":reset ", [])-- -- :show should complete to "loaded" and "import"- , (":show ", [":show import", ":show loaded"])- , (":show a", [])-- -- :type should complete values and data constructors in scope- , (":type Control.Monad.Eff.Console.lo", [":type Control.Monad.Eff.Console.log", ":type Control.Monad.Eff.Console.logShow"])- --, (":type uni", [":type unit"])- --, (":type E", [":type EQ"])-- -- :kind should complete types in scope- --, (":kind C", [":kind Control.Monad.Eff.Pure"])- --, (":kind O", [":kind Ordering"])-- -- Only one argument for directives should be completed- , (":show import ", [])- , (":type EQ ", [])- , (":kind Ordering ", [])-- -- a few other import tests- , ("impor", ["import"])- , ("import ", map ("import " ++) supportModules)- , ("import Prelude ", [])-- -- String and number literals should not be completed- , ("\"hi", [])- , ("34", [])-- -- Identifiers and data constructors should be completed- --, ("uni", ["unit"])- , ("Control.Monad.Eff.Class.", ["Control.Monad.Eff.Class.liftEff"])- --, ("G", ["GT"])- , ("Data.Ordering.L", ["Data.Ordering.LT"])-- -- if a module is imported qualified, values should complete under the- -- qualified name, as well as the original name.- , ("ST.new", ["ST.newSTRef"])- , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])- ]--assertCompletedOk :: (String, [String]) -> Assertion-assertCompletedOk (line, expecteds) = do- (unusedR, completions) <- runCM (completion' (reverse line, ""))- let unused = reverse unusedR- let actuals = map ((unused ++) . replacement) completions- sort expecteds @=? sort actuals--runCM :: CompletionM a -> IO a-runCM act = do- psciState <- getPSCiState- evalStateT (liftCompletionM act) psciState--getPSCiState :: IO PSCiState-getPSCiState = do- cwd <- getCurrentDirectory- let supportDir = cwd </> "tests" </> "support" </> "bower_components"- let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/src/**/*." ++ ext)) supportDir- pursFiles <- supportFiles "purs"-- modulesOrFirstError <- loadAllModules pursFiles- case modulesOrFirstError of- Left err ->- print err >> exitFailure- Right modules ->- let imports = [controlMonadSTasST, (P.ModuleName [P.ProperName (T.pack "Prelude")], P.Implicit, Nothing)]- dummyExterns = P.internalError "TestPsci: dummyExterns should not be used"- in return (PSCiState imports [] (zip (map snd modules) (repeat dummyExterns)))--controlMonadSTasST :: ImportedModule-controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))- where- s = P.moduleNameFromString . T.pack+allTests = TestList [ completionTests+ , commandTests+ ]
+ tests/TestPsci/CommandTest.hs view
@@ -0,0 +1,35 @@+module TestPsci.CommandTest where++import Prelude ()+import Prelude.Compat++import Control.Monad.Trans.RWS.Strict (get)+import Language.PureScript.Interactive+import Test.HUnit+import TestPsci.TestEnv++commandTests :: Test+commandTests = TestLabel "commandTests" $ TestList $ map (TestCase . execTestPSCi)+ [ do+ run "import Prelude"+ run "import Data.Functor"+ run "import Control.Monad"+ before <- psciImportedModules <$> get+ length before `equalsTo` 3+ run ":clear"+ after <- psciImportedModules <$> get+ length after `equalsTo` 0+ , do+ run "import Prelude"+ run "import Data.Functor"+ run "import Control.Monad"+ before <- psciImportedModules <$> get+ length before `equalsTo` 3+ run ":reload"+ after <- psciImportedModules <$> get+ length after `equalsTo` 3+ , do+ run "import Prelude"+ run "import Data.Array"+ "let fac n = foldl mul 1 (1..n) in fac 10" `evaluatesTo` "3628800"+ ]
+ tests/TestPsci/CompletionTest.hs view
@@ -0,0 +1,108 @@+module TestPsci.CompletionTest where++import Prelude ()+import Prelude.Compat++import Test.HUnit++import Control.Monad.Trans.State.Strict (evalStateT)+import Data.List (sort)+import qualified Data.Text as T+import qualified Language.PureScript as P+import Language.PureScript.Interactive+import System.Console.Haskeline+import TestPsci.TestEnv (initTestPSCiEnv)+import TestUtils (supportModules)++completionTests :: Test+completionTests =+ TestLabel "completionTests"+ (TestList (map (TestCase . assertCompletedOk) completionTestData))++-- If the cursor is at the right end of the line, with the 1st element of the+-- pair as the text in the line, then pressing tab should offer all the+-- elements of the list (which is the 2nd element) as completions.+completionTestData :: [(String, [String])]+completionTestData =+ -- basic directives+ [ (":h", [":help"])+ , (":r", [":reload"])+ , (":c", [":clear"])+ , (":q", [":quit"])+ , (":b", [":browse"])++ -- :browse should complete module names+ , (":b Control.Monad.E", map (":b Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])+ , (":b Control.Monad.Eff.", map (":b Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])++ -- import should complete module names+ , ("import Control.Monad.E", map ("import Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])+ , ("import Control.Monad.Eff.", map ("import Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])++ -- :quit, :help, :reload, :clear should not complete+ , (":help ", [])+ , (":quit ", [])+ , (":reload ", [])+ , (":clear ", [])++ -- :show should complete to "loaded" and "import"+ , (":show ", [":show import", ":show loaded"])+ , (":show a", [])++ -- :type should complete values and data constructors in scope+ , (":type Control.Monad.Eff.Console.lo", [":type Control.Monad.Eff.Console.log", ":type Control.Monad.Eff.Console.logShow"])+ --, (":type uni", [":type unit"])+ --, (":type E", [":type EQ"])++ -- :kind should complete types in scope+ --, (":kind C", [":kind Control.Monad.Eff.Pure"])+ --, (":kind O", [":kind Ordering"])++ -- Only one argument for directives should be completed+ , (":show import ", [])+ , (":type EQ ", [])+ , (":kind Ordering ", [])++ -- a few other import tests+ , ("impor", ["import"])+ , ("import ", map ("import " ++) supportModules)+ , ("import Prelude ", [])++ -- String and number literals should not be completed+ , ("\"hi", [])+ , ("34", [])++ -- Identifiers and data constructors should be completed+ --, ("uni", ["unit"])+ , ("Control.Monad.Eff.Class.", ["Control.Monad.Eff.Class.liftEff"])+ --, ("G", ["GT"])+ , ("Data.Ordering.L", ["Data.Ordering.LT"])++ -- if a module is imported qualified, values should complete under the+ -- qualified name, as well as the original name.+ , ("ST.new", ["ST.newSTRef"])+ , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])+ ]++assertCompletedOk :: (String, [String]) -> Assertion+assertCompletedOk (line, expecteds) = do+ (unusedR, completions) <- runCM (completion' (reverse line, ""))+ let unused = reverse unusedR+ let actuals = map ((unused ++) . replacement) completions+ sort expecteds @=? sort actuals++runCM :: CompletionM a -> IO a+runCM act = do+ psciState <- getPSCiStateForCompletion+ evalStateT (liftCompletionM act) psciState++getPSCiStateForCompletion :: IO PSCiState+getPSCiStateForCompletion = do+ (PSCiState _ bs es, _) <- initTestPSCiEnv+ let imports = [controlMonadSTasST, (P.ModuleName [P.ProperName (T.pack "Prelude")], P.Implicit, Nothing)]+ return $ PSCiState imports bs es++controlMonadSTasST :: ImportedModule+controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))+ where+ s = P.moduleNameFromString . T.pack
+ tests/TestPsci/TestEnv.hs view
@@ -0,0 +1,81 @@+module TestPsci.TestEnv where++import Prelude ()+import Prelude.Compat++import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.RWS.Strict (evalRWST, RWST)+import qualified Language.PureScript as P+import Language.PureScript.Interactive+import System.Directory (getCurrentDirectory)+import System.Exit+import System.FilePath ((</>))+import qualified System.FilePath.Glob as Glob+import System.Process (readProcessWithExitCode)+import Test.HUnit ((@?=))++-- | A monad transformer for handle PSCi actions in tests+type TestPSCi a = RWST PSCiConfig () PSCiState IO a++-- | Initialise PSCi state and config for tests+initTestPSCiEnv :: IO (PSCiState, PSCiConfig)+initTestPSCiEnv = do+ -- Load test support packages+ cwd <- getCurrentDirectory+ let supportDir = cwd </> "tests" </> "support" </> "bower_components"+ let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/src/**/*." ++ ext)) supportDir+ pursFiles <- supportFiles "purs"+ modulesOrError <- loadAllModules pursFiles+ case modulesOrError of+ Left err ->+ print err >> exitFailure+ Right modules -> do+ -- Make modules+ makeResultOrError <- runMake . make $ modules+ case makeResultOrError of+ Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure+ Right (externs, env) ->+ return (PSCiState [] [] (zip (map snd modules) externs), PSCiConfig pursFiles env)++-- | Execute a TestPSCi, returning IO+execTestPSCi :: TestPSCi a -> IO a+execTestPSCi i = do+ (s, c) <- initTestPSCiEnv -- init state and config+ fst <$> evalRWST i c s++-- | Evaluate JS to which a PSCi input is compiled. The actual JS input is not+-- needed as an argument, as it is already written in the file during the+-- command evaluation.+jsEval :: TestPSCi String+jsEval = liftIO $ do+ writeFile indexFile "require('$PSCI')['$main']();"+ process <- findNodeProcess+ result <- traverse (\node -> readProcessWithExitCode node [indexFile] "") process+ case result of+ Just (ExitSuccess, out, _) -> return out+ Just (ExitFailure _, _, err) -> putStrLn err >> exitFailure+ Nothing -> putStrLn "Couldn't find node.js" >> exitFailure++-- | Run a PSCi command and evaluate the output with 'eval'.+runAndEval :: String -> TestPSCi () -> TestPSCi ()+runAndEval comm eval =+ case parseCommand comm of+ Left errStr -> liftIO $ putStrLn errStr >> exitFailure+ Right command ->+ -- the JS result can be ignored, as it's already written in a source file+ -- for the detail, please refer to Interactive.hs+ handleCommand (\_ -> eval) (return ()) command++-- | Run a PSCi command and ignore the output+run :: String -> TestPSCi ()+run comm = runAndEval comm $ jsEval *> return ()++-- | A lifted evaluation of HUnit '@?=' for the TestPSCi+equalsTo :: (Eq a, Show a) => a -> a -> TestPSCi ()+equalsTo x y = liftIO $ x @?= y++-- | An assertion to check if a command evaluates to a string+evaluatesTo :: String -> String -> TestPSCi ()+evaluatesTo command expected = runAndEval command $ do+ actual <- jsEval+ actual `equalsTo` (expected ++ "\n")
tests/TestUtils.hs view
@@ -105,6 +105,7 @@ , "Data.Functor.Invariant" , "Data.Generic" , "Data.Generic.Rep"+ , "Data.Generic.Rep.Bounded" , "Data.Generic.Rep.Eq" , "Data.Generic.Rep.Monoid" , "Data.Generic.Rep.Ord"@@ -146,6 +147,7 @@ , "Data.Unfoldable" , "Data.Unit" , "Data.Void"+ , "PSCI.Support" , "Partial" , "Partial.Unsafe" , "Prelude"
tests/support/bower.json view
@@ -1,18 +1,21 @@ { "name": "purescript-test-suite-support", "dependencies": {- "purescript-assert": "2.0.0",- "purescript-console": "2.0.0",- "purescript-eff": "2.0.0",- "purescript-functions": "2.0.0",- "purescript-prelude": "2.1.0",- "purescript-st": "2.0.0",- "purescript-partial": "1.1.2",- "purescript-newtype": "1.1.0",- "purescript-generics": "3.3.0",- "purescript-generics-rep": "4.0.0",- "purescript-symbols": "^2.0.0",- "purescript-typelevel-prelude": "https://github.com/purescript/purescript-typelevel-prelude.git#29a7123a0c29c85d4b923fcf4a7df8e45ebf9bac",- "purescript-unsafe-coerce": "^2.0.0"+ "purescript-arrays": "ps-0.11",+ "purescript-assert": "ps-0.11",+ "purescript-console": "ps-0.11",+ "purescript-eff": "ps-0.11",+ "purescript-functions": "ps-0.11",+ "purescript-generics": "ps-0.11",+ "purescript-generics-rep": "ps-0.11",+ "purescript-newtype": "ps-0.11",+ "purescript-partial": "1.2.0",+ "purescript-prelude": "ps-0.11",+ "purescript-psci-support": "ps-0.11",+ "purescript-st": "ps-0.11",+ "purescript-symbols": "ps-0.11",+ "purescript-tailrec": "ps-0.11",+ "purescript-typelevel-prelude": "ps-0.11",+ "purescript-unsafe-coerce": "ps-0.11" } }
+ tests/support/prelude-resolutions.json view
@@ -0,0 +1,7 @@+{+ "canonicalDir": "bower_components/purescript-prelude",+ "pkgMeta": {+ "dependencies": {}+ },+ "dependencies": {}+}