purescript 0.4.8 → 0.4.9
raw patch · 40 files changed
+862/−783 lines, 40 files
Files
- prelude/prelude.purs +24/−34
- psc-make/Main.hs +7/−7
- psc/Main.hs +7/−7
- psci/Main.hs +1/−2
- psci/Parser.hs +2/−2
- purescript.cabal +2/−4
- src/Language/PureScript.hs +62/−17
- src/Language/PureScript/CodeGen/Externs.hs +1/−1
- src/Language/PureScript/CodeGen/JS.hs +2/−2
- src/Language/PureScript/DeadCodeElimination.hs +0/−1
- src/Language/PureScript/Declarations.hs +194/−2
- src/Language/PureScript/Environment.hs +8/−1
- src/Language/PureScript/ModuleDependencies.hs +1/−1
- src/Language/PureScript/Optimizer/MagicDo.hs +14/−9
- src/Language/PureScript/Optimizer/TCO.hs +2/−2
- src/Language/PureScript/Options.hs +9/−5
- src/Language/PureScript/Parser.hs +0/−1
- src/Language/PureScript/Parser/Common.hs +9/−2
- src/Language/PureScript/Parser/Declarations.hs +240/−11
- src/Language/PureScript/Parser/Types.hs +1/−1
- src/Language/PureScript/Parser/Values.hs +0/−246
- src/Language/PureScript/Pretty/Types.hs +3/−5
- src/Language/PureScript/Pretty/Values.hs +2/−1
- src/Language/PureScript/Scope.hs +1/−1
- src/Language/PureScript/Sugar.hs +2/−7
- src/Language/PureScript/Sugar/BindingGroups.hs +14/−4
- src/Language/PureScript/Sugar/CaseDeclarations.hs +7/−2
- src/Language/PureScript/Sugar/DoNotation.hs +1/−1
- src/Language/PureScript/Sugar/Let.hs +0/−34
- src/Language/PureScript/Sugar/Names.hs +48/−29
- src/Language/PureScript/Sugar/Operators.hs +1/−1
- src/Language/PureScript/Sugar/TypeClasses.hs +4/−2
- src/Language/PureScript/Sugar/TypeDeclarations.hs +8/−1
- src/Language/PureScript/TypeChecker.hs +3/−3
- src/Language/PureScript/TypeChecker/Kinds.hs +13/−13
- src/Language/PureScript/TypeChecker/Monad.hs +1/−1
- src/Language/PureScript/TypeChecker/Types.hs +102/−54
- src/Language/PureScript/TypeClassDictionaries.hs +62/−0
- src/Language/PureScript/Types.hs +4/−12
- src/Language/PureScript/Values.hs +0/−254
prelude/prelude.purs view
@@ -139,24 +139,38 @@ (%) = numMod negate = numNegate - infixl 4 ==- infixl 4 /=+ infix 4 ==+ infix 4 /= class Eq a where (==) :: a -> a -> Boolean (/=) :: a -> a -> Boolean + foreign import refEq+ "function refEq(r1) {\+ \ return function(r2) {\+ \ return r1 === r2;\+ \ };\+ \}" :: forall a. a -> a -> Boolean++ foreign import refIneq+ "function refIneq(r1) {\+ \ return function(r2) {\+ \ return r1 !== r2;\+ \ };\+ \}" :: forall a. a -> a -> Boolean+ instance eqString :: Eq String where- (==) = Data.Eq.Unsafe.refEq- (/=) = Data.Eq.Unsafe.refIneq+ (==) = refEq+ (/=) = refIneq instance eqNumber :: Eq Number where- (==) = Data.Eq.Unsafe.refEq- (/=) = Data.Eq.Unsafe.refIneq+ (==) = refEq+ (/=) = refIneq instance eqBoolean :: Eq Boolean where- (==) = Data.Eq.Unsafe.refEq- (/=) = Data.Eq.Unsafe.refIneq+ (==) = refEq+ (/=) = refIneq instance eqArray :: (Eq a) => Eq [a] where (==) [] [] = true@@ -321,38 +335,14 @@ module Data.Eq where - import qualified Data.Eq.Unsafe as Unsafe- data Ref a = Ref a liftRef :: forall a b. (a -> a -> b) -> Ref a -> Ref a -> b liftRef f (Ref x) (Ref y) = f x y - refEq :: forall a. Ref a -> Ref a -> Boolean- refEq = liftRef Unsafe.refEq-- refIneq :: forall a. Ref a -> Ref a -> Boolean- refIneq = liftRef Unsafe.refIneq- instance eqRef :: Eq (Ref a) where- (==) = refEq- (/=) = refIneq- -module Data.Eq.Unsafe where-- foreign import refEq- "function refEq(r1) {\- \ return function(r2) {\- \ return r1 === r2;\- \ };\- \}" :: forall a. a -> a -> Boolean-- foreign import refIneq- "function refIneq(r1) {\- \ return function(r2) {\- \ return r1 !== r2;\- \ };\- \}" :: forall a. a -> a -> Boolean+ (==) = liftRef refEq+ (/=) = liftRef refIneq module Control.Monad.Eff where
psc-make/Main.hs view
@@ -91,9 +91,9 @@ inputFiles = value $ posAny [] $ posInfo { posDoc = "The input .ps files" } -tco :: Term Bool-tco = value $ flag $ (optInfo [ "tco" ])- { optDoc = "Perform tail call optimizations" }+noTco :: Term Bool+noTco = value $ flag $ (optInfo [ "no-tco" ])+ { optDoc = "Disable tail call optimizations" } performRuntimeTypeChecks :: Term Bool performRuntimeTypeChecks = value $ flag $ (optInfo [ "runtime-type-checks" ])@@ -103,9 +103,9 @@ noPrelude = value $ flag $ (optInfo [ "no-prelude" ]) { optDoc = "Omit the Prelude" } -magicDo :: Term Bool-magicDo = value $ flag $ (optInfo [ "magic-do" ])- { optDoc = "Overload the do keyword to generate efficient code specifically for the Eff monad." }+noMagicDo :: Term Bool+noMagicDo = value $ flag $ (optInfo [ "no-magic-do" ])+ { optDoc = "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad." } noOpts :: Term Bool noOpts = value $ flag $ (optInfo [ "no-opts" ])@@ -116,7 +116,7 @@ { optDoc = "Specify the namespace that PureScript modules will be exported to when running in the browser." } options :: Term P.Options-options = P.Options <$> tco <*> performRuntimeTypeChecks <*> magicDo <*> pure Nothing <*> noOpts <*> browserNamespace <*> pure [] <*> pure []+options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> pure Nothing <*> noOpts <*> browserNamespace <*> pure [] <*> pure [] inputFilesAndPrelude :: FilePath -> Term [FilePath] inputFilesAndPrelude prelude = combine <$> (not <$> noPrelude) <*> inputFiles
psc/Main.hs view
@@ -86,9 +86,9 @@ externsFile = value $ opt Nothing $ (optInfo [ "e", "externs" ]) { optDoc = "The output .e.ps file" } -tco :: Term Bool-tco = value $ flag $ (optInfo [ "tco" ])- { optDoc = "Perform tail call optimizations" }+noTco :: Term Bool+noTco = value $ flag $ (optInfo [ "no-tco" ])+ { optDoc = "Disable tail call optimizations" } performRuntimeTypeChecks :: Term Bool performRuntimeTypeChecks = value $ flag $ (optInfo [ "runtime-type-checks" ])@@ -98,9 +98,9 @@ noPrelude = value $ flag $ (optInfo [ "no-prelude" ]) { optDoc = "Omit the Prelude" } -magicDo :: Term Bool-magicDo = value $ flag $ (optInfo [ "magic-do" ])- { optDoc = "Overload the do keyword to generate efficient code specifically for the Eff monad." }+noMagicDo :: Term Bool+noMagicDo = value $ flag $ (optInfo [ "no-magic-do" ])+ { optDoc = "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad." } runMain :: Term (Maybe String) runMain = value $ defaultOpt (Just "Main") Nothing $ (optInfo [ "main" ])@@ -123,7 +123,7 @@ { optDoc = "A list of modules for which Javascript and externs should be generated. This argument can be used multiple times." } options :: Term P.Options-options = P.Options <$> tco <*> performRuntimeTypeChecks <*> magicDo <*> runMain <*> noOpts <*> browserNamespace <*> dceModules <*> codeGenModules+options = P.Options <$> noPrelude <*> noTco <*> performRuntimeTypeChecks <*> noMagicDo <*> runMain <*> noOpts <*> browserNamespace <*> dceModules <*> codeGenModules stdInOrInputFiles :: FilePath -> Term (Maybe [FilePath]) stdInOrInputFiles prelude = combine <$> useStdIn <*> (not <$> noPrelude) <*> inputFiles
psci/Main.hs view
@@ -161,7 +161,6 @@ -- | -- Loads module, function, and file completions.--- TODO: filter names to only include exported decls -- completion :: CompletionFunc (StateT PSCiState IO) completion = completeWord Nothing " \t\n\r" findCompletions@@ -195,7 +194,7 @@ -- | Compilation options. -- options :: P.Options-options = P.Options True False True (Just "Main") True "PS" [] []+options = P.Options False True False True (Just "Main") True "PS" [] [] -- | -- Makes a volatile module to execute the current expression.
psci/Parser.hs view
@@ -26,6 +26,7 @@ import Text.Parsec hiding ((<|>)) import qualified Language.PureScript as P+import qualified Language.PureScript.Parser.Common as C (mark, same) -- | -- PSCI version of @let@.@@ -34,8 +35,7 @@ -- we actually want the normal @let@. -- psciLet :: Parsec String P.ParseState Command-psciLet = Let <$> (P.Let <$> (P.reserved "let" *> P.indented *> (Left <$> P.parseBinder))- <*> (P.indented *> P.reservedOp "=" *> P.parseValue))+psciLet = Let <$> (P.Let <$> (P.reserved "let" *> P.indented *> C.mark (many1 (C.same *> P.parseDeclaration)))) -- | -- Parses PSCI metacommands or expressions input from the user.
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.4.8+version: 0.4.9 cabal-version: >=1.8 build-type: Custom license: MIT@@ -33,8 +33,8 @@ Language.PureScript.Kinds Language.PureScript.Names Language.PureScript.Types- Language.PureScript.Values Language.PureScript.Scope+ Language.PureScript.TypeClassDictionaries Language.PureScript.DeadCodeElimination Language.PureScript.Sugar Language.PureScript.ModuleDependencies@@ -44,7 +44,6 @@ Language.PureScript.Sugar.BindingGroups Language.PureScript.Sugar.Operators Language.PureScript.Sugar.TypeClasses- Language.PureScript.Sugar.Let Language.PureScript.Sugar.Names Language.PureScript.CodeGen Language.PureScript.CodeGen.Common@@ -65,7 +64,6 @@ Language.PureScript.Parser.Kinds Language.PureScript.Parser.State Language.PureScript.Parser.Types- Language.PureScript.Parser.Values Language.PureScript.Pretty Language.PureScript.Pretty.Common Language.PureScript.Pretty.JS
src/Language/PureScript.hs view
@@ -15,7 +15,6 @@ module Language.PureScript (module P, compile, compile', MonadMake(..), make) where -import Language.PureScript.Values as P import Language.PureScript.Types as P import Language.PureScript.Kinds as P import Language.PureScript.Declarations as P@@ -33,13 +32,15 @@ import qualified Language.PureScript.Constants as C -import Data.List (sortBy, groupBy, intercalate)+import Data.List (find, sortBy, groupBy, intercalate) import Data.Time.Clock import Data.Function (on)+import Data.Generics (mkQ, everything) import Data.Maybe (fromMaybe, mapMaybe)+import Control.Monad.Error import Control.Monad.State.Lazy import Control.Arrow ((&&&))-import Control.Applicative ((<$>), (<*>), pure)+import Control.Applicative ((<$>)) import qualified Data.Map as M import qualified Data.Set as S import System.FilePath (pathSeparator)@@ -68,11 +69,9 @@ compile' :: Environment -> Options -> [Module] -> Either String (String, String, Environment) compile' env opts ms = do- (sorted, _) <- sortModules ms+ (sorted, _) <- sortModules $ if optionsNoPrelude opts then ms else (map importPrelude ms) desugared <- desugar sorted- (elaborated, env') <- runCheck' env $ forM desugared $ \(Module moduleName' decls exps) -> do- modify (\s -> s { checkCurrentModule = Just moduleName' })- Module moduleName' <$> typeCheckAll mainModuleIdent moduleName' decls <*> pure exps+ (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated let entryPoints = moduleNameFromString `map` optionsModules opts let elim = if null entryPoints then regrouped else eliminateDeadCode entryPoints regrouped@@ -85,6 +84,42 @@ where mainModuleIdent = moduleNameFromString <$> optionsMain opts +typeCheckModule :: Maybe ModuleName -> Module -> Check Module+typeCheckModule mainModuleName (Module mn decls exps) = do+ modify (\s -> s { checkCurrentModule = Just mn })+ decls' <- typeCheckAll mainModuleName mn decls+ mapM_ checkTypesAreExported exps'+ return $ Module mn decls' exps+ where++ exps' = fromMaybe (error "exports should have been elaborated") exps++ -- Check that all the type constructors defined in the current module that appear in member types+ -- have also been exported from the module+ checkTypesAreExported :: DeclarationRef -> Check ()+ checkTypesAreExported (ValueRef name) = do+ ty <- lookupVariable mn (Qualified (Just mn) name)+ case find isTconHidden (findTcons ty) of+ Just hiddenType -> throwError $ "Error in module '" ++ show mn ++ "':\n\+ \Exporting declaration '" ++ show name ++ "' requires type '" ++ show hiddenType ++ "' to be exported as well"+ Nothing -> return ()+ checkTypesAreExported _ = return ()++ -- Find the type constructors exported from the current module used in a type+ findTcons :: Type -> [ProperName]+ findTcons = everything (++) (mkQ [] go)+ where+ go (TypeConstructor (Qualified (Just mn') name)) | mn' == mn = [name]+ go _ = []++ -- Checks whether a type constructor is not being exported from the current module+ isTconHidden :: ProperName -> Bool+ isTconHidden tyName = all go exps'+ where+ go (TypeRef tyName' _) = tyName' /= tyName+ go _ = True+ + generateMain :: Environment -> Options -> [JS] -> Either String [JS] generateMain env opts js = case moduleNameFromString <$> optionsMain opts of@@ -127,9 +162,9 @@ -- make :: (Functor m, Monad m, MonadMake m) => Options -> [(FilePath, Module)] -> m () make opts ms = do- let filePathMap = M.fromList (map (\(fp, (Module mn _ _)) -> (mn, fp)) ms)+ let filePathMap = M.fromList (map (\(fp, Module mn _ _) -> (mn, fp)) ms) - (sorted, graph) <- liftError $ sortModules (map snd ms)+ (sorted, graph) <- liftError $ sortModules $ if optionsNoPrelude opts then map snd ms else (map (importPrelude . snd) ms) toRebuild <- foldM (\s (Module moduleName' _ _) -> do let filePath = toFileName moduleName'@@ -155,20 +190,16 @@ where go :: (Functor m, Monad m, MonadMake m) => Environment -> [(Bool, Module)] -> m () go _ [] = return ()- go env ((False, Module moduleName' typings _) : ms') = do- (_, env') <- liftError . runCheck' env $ do- modify (\s -> s { checkCurrentModule = Just moduleName' })- typeCheckAll Nothing moduleName' typings+ go env ((False, m) : ms') = do+ (_, env') <- liftError . runCheck' env $ typeCheckModule Nothing m go env' ms'- go env ((True, Module moduleName' decls exps) : ms') = do+ go env ((True, m@(Module moduleName' _ exps)) : ms') = do let filePath = toFileName moduleName' jsFile = "js" ++ pathSeparator : filePath ++ ".js" externsFile = "externs" ++ pathSeparator : filePath ++ ".externs" - (elaborated, env') <- liftError . runCheck' env $ do- modify (\s -> s { checkCurrentModule = Just moduleName' })- typeCheckAll Nothing moduleName' decls+ (Module _ elaborated _, env') <- liftError . runCheck' env $ typeCheckModule Nothing m regrouped <- liftError . createBindingGroups moduleName' . collapseBindingGroups $ elaborated @@ -204,3 +235,17 @@ where combine :: (Ord a) => [(a, b)] -> M.Map a [b] combine = M.fromList . map ((fst . head) &&& map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst)++-- |+-- Add an import declaration for the Prelude to a module if it does not already explicitly import+-- it.+--+importPrelude :: Module -> Module+importPrelude m@(Module mn decls exps) =+ if isPreludeImport `any` decls || mn == prelude then m+ else Module mn (preludeImport : decls) exps+ where+ prelude = ModuleName [ProperName C.prelude]+ isPreludeImport (ImportDeclaration (ModuleName [ProperName mn']) _ _) | mn' == C.prelude = True+ isPreludeImport _ = False+ preludeImport = ImportDeclaration prelude Nothing Nothing
src/Language/PureScript/CodeGen/Externs.hs view
@@ -24,10 +24,10 @@ import Control.Monad.Writer +import Language.PureScript.TypeClassDictionaries import Language.PureScript.Declarations import Language.PureScript.Pretty import Language.PureScript.Names-import Language.PureScript.Values import Language.PureScript.Environment -- |
src/Language/PureScript/CodeGen/JS.hs view
@@ -30,7 +30,6 @@ import qualified Data.Map as M -import Language.PureScript.Values import Language.PureScript.Names import Language.PureScript.Scope import Language.PureScript.Declarations@@ -134,6 +133,7 @@ valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el) valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val) valueToJs opts m e (App val arg) = JSApp (valueToJs opts m e val) [valueToJs opts m e arg]+valueToJs opts m e (Let ds val) = JSApp (JSFunction Nothing [] (JSBlock (concat (mapMaybe (flip (declToJs opts m) e) ds) ++ [JSReturn $ valueToJs opts m e val]))) [] valueToJs opts m e (Abs (Left arg) val) = JSFunction Nothing [identToJs arg] (JSBlock [JSReturn (valueToJs opts m (bindName m arg e) val)]) valueToJs opts m e (TypedValue _ (Abs (Left arg) val) ty) | optionsPerformRuntimeTypeChecks opts = let arg' = identToJs arg in JSFunction Nothing [arg'] (JSBlock $ runtimeTypeChecks arg' ty ++ [JSReturn (valueToJs opts m e val)]) valueToJs _ m _ (Var ident) = varToJs m ident@@ -193,7 +193,7 @@ argumentCheck val t | t == tyString = [typeCheck val "string"] argumentCheck val t | t == tyBoolean = [typeCheck val "boolean"] argumentCheck val (TypeApp t _) | t == tyArray = [arrayCheck val]- argumentCheck val (Object row) =+ argumentCheck val (TypeApp t row) | t == tyObject = let (pairs, _) = rowToList row in
src/Language/PureScript/DeadCodeElimination.hs view
@@ -23,7 +23,6 @@ import Data.Maybe (mapMaybe) import Language.PureScript.Names-import Language.PureScript.Values import Language.PureScript.Declarations -- |
src/Language/PureScript/Declarations.hs view
@@ -16,14 +16,15 @@ module Language.PureScript.Declarations where -import Language.PureScript.Values import Language.PureScript.Types import Language.PureScript.Names import Language.PureScript.Kinds+import Language.PureScript.TypeClassDictionaries import Language.PureScript.CodeGen.JS.AST import Language.PureScript.Environment import qualified Data.Data as D+import Data.Generics (mkQ, everything) -- | -- A precedence level for an infix operator@@ -33,11 +34,12 @@ -- | -- Associativity for infix operators ---data Associativity = Infixl | Infixr deriving (D.Data, D.Typeable)+data Associativity = Infixl | Infixr | Infix deriving (D.Data, D.Typeable) instance Show Associativity where show Infixl = "infixl" show Infixr = "infixr"+ show Infix = "infix" -- | -- Fixity data for infix operators@@ -189,3 +191,193 @@ isTypeClassDeclaration TypeClassDeclaration{} = True isTypeClassDeclaration TypeInstanceDeclaration{} = True isTypeClassDeclaration _ = False++-- |+-- A guard is just a boolean-valued expression that appears alongside a set of binders+--+type Guard = Value++-- |+-- Data type for values+--+data Value+ -- |+ -- A numeric literal+ --+ = NumericLiteral (Either Integer Double)+ -- |+ -- A string literal+ --+ | StringLiteral String+ -- |+ -- A boolean literal+ --+ | BooleanLiteral Bool+ -- |+ -- Binary operator application. During the rebracketing phase of desugaring, this data constructor+ -- will be removed.+ --+ | BinaryNoParens (Qualified Ident) Value Value+ -- |+ -- Explicit parentheses. During the rebracketing phase of desugaring, this data constructor+ -- will be removed.+ --+ | Parens Value+ -- |+ -- An array literal+ --+ | ArrayLiteral [Value]+ -- |+ -- An object literal+ --+ | ObjectLiteral [(String, Value)]+ -- |+ -- An record property accessor expression+ --+ | Accessor String Value+ -- |+ -- Partial record update+ --+ | ObjectUpdate Value [(String, Value)]+ -- |+ -- Function introduction+ --+ | Abs (Either Ident Binder) Value+ -- |+ -- Function application+ --+ | App Value Value+ -- |+ -- Variable+ --+ | Var (Qualified Ident)+ -- |+ -- Conditional (if-then-else expression)+ --+ | IfThenElse Value Value Value+ -- |+ -- A data constructor+ --+ | Constructor (Qualified ProperName)+ -- |+ -- A case expression. During the case expansion phase of desugaring, top-level binders will get+ -- desugared into case expressions, hence the need for guards and multiple binders per branch here.+ --+ | Case [Value] [CaseAlternative]+ -- |+ -- A value with a type annotation+ --+ | TypedValue Bool Value Type+ -- |+ -- A let binding+ --+ | Let [Declaration] Value+ -- |+ -- A do-notation block+ --+ | Do [DoNotationElement]+ -- |+ -- A placeholder for a type class dictionary to be inserted later. At the end of type checking, these+ -- placeholders will be replaced with actual expressions representing type classes dictionaries which+ -- can be evaluated at runtime. The constructor arguments represent (in order): the type class name and+ -- instance type, and the type class dictionaries in scope.+ --+ | TypeClassDictionary (Qualified ProperName, [Type]) [TypeClassDictionaryInScope] deriving (Show, D.Data, D.Typeable)++-- |+-- An alternative in a case statement+--+data CaseAlternative = CaseAlternative+ { -- |+ -- A collection of binders with which to match the inputs+ --+ caseAlternativeBinders :: [Binder]+ -- |+ -- An optional guard+ --+ , caseAlternativeGuard :: Maybe Guard+ -- |+ -- The result expression+ --+ , caseAlternativeResult :: Value+ } deriving (Show, D.Data, D.Typeable)++-- |+-- Find the original dictionary which a type class dictionary in scope refers to+--+canonicalizeDictionary :: TypeClassDictionaryInScope -> Qualified Ident+canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDRegular, tcdName = nm }) = nm+canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDAlias nm }) = nm++-- |+-- A statement in a do-notation block+--+data DoNotationElement+ -- |+ -- A monadic value without a binder+ --+ = DoNotationValue Value+ -- |+ -- A monadic value with a binder+ --+ | DoNotationBind Binder Value+ -- |+ -- A let statement, i.e. a pure value with a binder+ --+ | DoNotationLet Binder Value deriving (Show, D.Data, D.Typeable)++-- |+-- Data type for binders+--+data Binder+ -- |+ -- Wildcard binder+ --+ = NullBinder+ -- |+ -- A binder which matches a boolean literal+ --+ | BooleanBinder Bool+ -- |+ -- A binder which matches a string literal+ --+ | StringBinder String+ -- |+ -- A binder which matches a numeric literal+ --+ | NumberBinder (Either Integer Double)+ -- |+ -- A binder which binds an identifier+ --+ | VarBinder Ident+ -- |+ -- A binder which matches a data constructor+ --+ | ConstructorBinder (Qualified ProperName) [Binder]+ -- |+ -- A binder which matches a record and binds its properties+ --+ | ObjectBinder [(String, Binder)]+ -- |+ -- A binder which matches an array and binds its elements+ --+ | ArrayBinder [Binder]+ -- |+ -- A binder which matches an array and binds its head and tail+ --+ | ConsBinder Binder Binder+ -- |+ -- A binder which binds its input to an identifier+ --+ | NamedBinder Ident Binder deriving (Show, D.Data, D.Typeable)+++-- |+-- Collect all names introduced in binders in an expression+--+binderNames :: (D.Data d) => d -> [Ident]+binderNames = everything (++) (mkQ [] go)+ where+ go (VarBinder ident) = [ident]+ go (NamedBinder ident _) = [ident]+ go _ = []
src/Language/PureScript/Environment.hs view
@@ -21,7 +21,7 @@ import Language.PureScript.Names import Language.PureScript.Types import Language.PureScript.Kinds-import Language.PureScript.Values+import Language.PureScript.TypeClassDictionaries import qualified Language.PureScript.Constants as C import qualified Data.Map as M@@ -172,6 +172,12 @@ tyArray = primTy "Array" -- |+-- Type constructor for objects+--+tyObject :: Type+tyObject = primTy "Object"++-- | -- Smart constructor for function types -- function :: Type -> Type -> Type@@ -183,6 +189,7 @@ primTypes :: M.Map (Qualified ProperName) (Kind, TypeKind) primTypes = M.fromList [ (primName "Function" , (FunKind Star (FunKind Star Star), ExternData)) , (primName "Array" , (FunKind Star Star, ExternData))+ , (primName "Object" , (FunKind (Row Star) Star, ExternData)) , (primName "String" , (Star, ExternData)) , (primName "Number" , (Star, ExternData)) , (primName "Boolean" , (Star, ExternData)) ]
src/Language/PureScript/ModuleDependencies.hs view
@@ -67,4 +67,4 @@ toModule :: SCC Module -> Either String Module toModule (AcyclicSCC m) = return m toModule (CyclicSCC [m]) = return m-toModule (CyclicSCC _) = Left "Cycle in module dependencies"+toModule (CyclicSCC ms) = Left $ "Cycle in module dependencies: " ++ show (map getModuleName ms)
src/Language/PureScript/Optimizer/MagicDo.hs view
@@ -30,8 +30,8 @@ import qualified Language.PureScript.Constants as C magicDo :: Options -> JS -> JS-magicDo opts | optionsMagicDo opts = inlineST . magicDo'- | otherwise = id+magicDo opts | optionsNoMagicDo opts = id+ | otherwise = inlineST . magicDo' -- | -- Inline type class dictionaries for >>= and return for the Eff monad@@ -58,12 +58,14 @@ convert :: JS -> JS -- Desugar return convert (JSApp (JSApp ret [val]) []) | isReturn ret = val- -- Desugae >>- convert (JSApp (JSApp bind [m]) [JSFunction Nothing ["_"] (JSBlock [JSReturn ret])]) | isBind bind =- JSFunction (Just fnName) [] $ JSBlock [ JSApp m [], JSReturn (JSApp ret []) ]+ -- Desugar >>+ convert (JSApp (JSApp bind [m]) [JSFunction Nothing ["_"] (JSBlock js)]) | isBind bind && isJSReturn (last js) =+ let JSReturn ret = last js in+ JSFunction (Just fnName) [] $ JSBlock (JSApp m [] : init js ++ [JSReturn (JSApp ret [])] ) -- Desugar >>=- convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock [JSReturn ret])]) | isBind bind =- JSFunction (Just fnName) [] $ JSBlock [ JSVariableIntroduction arg (Just (JSApp m [])), JSReturn (JSApp ret []) ]+ convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock js)]) | isBind bind && isJSReturn (last js) =+ let JSReturn ret = last js in+ JSFunction (Just fnName) [] $ JSBlock (JSVariableIntroduction arg (Just (JSApp m [])) : init js ++ [JSReturn (JSApp ret [])] ) -- Desugar untilE convert (JSApp (JSApp f [arg]) []) | isEffFunc C.untilE f = JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn (JSObjectLiteral []) ])) []@@ -109,6 +111,9 @@ undo (JSReturn (JSApp (JSFunction (Just ident) [] body) [])) | ident == fnName = body undo other = other + isJSReturn (JSReturn _) = True+ isJSReturn _ = False+ -- | -- Inline functions in the ST module --@@ -128,8 +133,8 @@ -- 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 (JSApp f [arg]) []) | isSTFunc C.newSTRef f =- if agg then arg else JSObjectLiteral [(C.stRefValue, arg)]+ convert agg (JSApp f [arg]) | isSTFunc C.newSTRef f =+ JSFunction Nothing [] (JSBlock [JSReturn $ if agg then arg else JSObjectLiteral [(C.stRefValue, arg)]]) convert agg (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f = if agg then ref else JSAccessor C.stRefValue ref convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
src/Language/PureScript/Optimizer/TCO.hs view
@@ -24,8 +24,8 @@ -- Eliminate tail calls -- tco :: Options -> JS -> JS-tco opts | optionsTco opts = tco'- | otherwise = id+tco opts | optionsNoTco opts = id+ | otherwise = tco' tco' :: JS -> JS tco' = everywhere (mkT convert)
src/Language/PureScript/Options.hs view
@@ -20,17 +20,21 @@ -- data Options = Options { -- |- -- Perform tail-call elimination+ -- Disable inclusion of the built in Prelude --- optionsTco :: Bool+ optionsNoPrelude :: Bool -- |+ -- Disable tail-call elimination+ --+ , optionsNoTco :: Bool+ -- | -- Perform type checks at runtime -- , optionsPerformRuntimeTypeChecks :: Bool -- |- -- Inline calls to ret and bind for the Eff monad+ -- Disable inlining of calls to return and bind for the Eff monad --- , optionsMagicDo :: Bool+ , optionsNoMagicDo :: Bool -- | -- When specified, checks the type of `main` in the module, and generate a call to run main -- after the module definitions.@@ -59,4 +63,4 @@ -- Default compiler options -- defaultOptions :: Options-defaultOptions = Options False False False Nothing False "PS" [] []+defaultOptions = Options False False False False Nothing False "PS" [] []
src/Language/PureScript/Parser.hs view
@@ -29,7 +29,6 @@ import Language.PureScript.Parser.Common as P import Language.PureScript.Parser.Types as P-import Language.PureScript.Parser.Values as P import Language.PureScript.Parser.State as P import Language.PureScript.Parser.Kinds as P import Language.PureScript.Parser.Declarations as P
src/Language/PureScript/Parser/Common.hs view
@@ -36,6 +36,7 @@ , "import" , "infixl" , "infixr"+ , "infix" , "class" , "instance" , "module"@@ -226,8 +227,14 @@ -- Parse an integer or floating point value -- integerOrFloat :: P.Parsec String u (Either Integer Double)-integerOrFloat = (Right <$> P.try (PT.float tokenParser) <|>- Left <$> P.try (PT.natural tokenParser)) P.<?> "number"+integerOrFloat = (Right <$> P.try (signed PT.float) <|>+ Left <$> P.try (signed PT.natural)) P.<?> "number"+ where+ signed p = do+ let sign = (P.char '-' >> return negate) <|> (optional (P.char '+') >> return id)+ f <- sign+ n <- p tokenParser+ return (f n) -- | -- Parse an identifier or parenthesized operator
src/Language/PureScript/Parser/Declarations.hs view
@@ -16,22 +16,28 @@ module Language.PureScript.Parser.Declarations ( parseDeclaration, parseModule,- parseModules+ parseModules,+ parseValue,+ parseGuard,+ parseBinder,+ parseBinderNoParens, ) where import Data.Maybe (isJust, fromMaybe) import Control.Applicative-import qualified Text.Parsec as P import Language.PureScript.Parser.State import Language.PureScript.Parser.Common import Language.PureScript.Declarations-import Language.PureScript.Parser.Values import Language.PureScript.Parser.Types import Language.PureScript.Parser.Kinds import Language.PureScript.CodeGen.JS.AST import Language.PureScript.Environment +import qualified Language.PureScript.Parser.Common as C+import qualified Text.Parsec as P+import qualified Text.Parsec.Expr as P+ parseDataDeclaration :: P.Parsec String ParseState Declaration parseDataDeclaration = do reserved "data"@@ -54,12 +60,17 @@ <*> (lexeme (indented *> P.char '=') *> parsePolyType) parseValueDeclaration :: P.Parsec String ParseState Declaration-parseValueDeclaration =- ValueDeclaration <$> parseIdent- <*> pure Value- <*> P.many parseBinderNoParens- <*> P.optionMaybe parseGuard- <*> (lexeme (indented *> P.char '=') *> parseValue)+parseValueDeclaration = do+ name <- parseIdent+ binders <- P.many parseBinderNoParens+ guard <- P.optionMaybe parseGuard+ value <- lexeme (indented *> P.char '=') *> parseValue+ whereClause <- P.optionMaybe $ do+ C.indented+ reserved "where"+ C.indented+ C.mark $ P.many1 (C.same *> parseLocalDeclaration)+ return $ ValueDeclaration name Value binders guard (maybe value (`Let` value) whereClause) parseExternDeclaration :: P.Parsec String ParseState Declaration parseExternDeclaration = P.try (reserved "foreign") *> indented *> reserved "import" *> indented *>@@ -83,7 +94,8 @@ parseAssociativity :: P.Parsec String ParseState Associativity parseAssociativity = (P.try (reserved "infixl") >> return Infixl) <|>- (P.try (reserved "infixr") >> return Infixr)+ (P.try (reserved "infixr") >> return Infixr) <|>+ (P.try (reserved "infix") >> return Infix) parseFixity :: P.Parsec String ParseState Fixity parseFixity = Fixity <$> parseAssociativity <*> (indented *> natural)@@ -159,8 +171,15 @@ , parseFixityDeclaration , parseImportDeclaration , parseTypeClassDeclaration- , parseTypeInstanceDeclaration ] P.<?> "declaration"+ , parseTypeInstanceDeclaration+ ] P.<?> "declaration" +parseLocalDeclaration :: P.Parsec String ParseState Declaration+parseLocalDeclaration = P.choice+ [ parseTypeDeclaration+ , parseValueDeclaration+ ] P.<?> "local declaration"+ -- | -- Parse a module header and a collection of declarations --@@ -179,3 +198,213 @@ -- parseModules :: P.Parsec String ParseState [Module] parseModules = whiteSpace *> mark (P.many (same *> parseModule)) <* P.eof++booleanLiteral :: P.Parsec String ParseState Bool+booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)++parseNumericLiteral :: P.Parsec String ParseState Value+parseNumericLiteral = NumericLiteral <$> C.integerOrFloat++parseStringLiteral :: P.Parsec String ParseState Value+parseStringLiteral = StringLiteral <$> C.stringLiteral++parseBooleanLiteral :: P.Parsec String ParseState Value+parseBooleanLiteral = BooleanLiteral <$> booleanLiteral++parseArrayLiteral :: P.Parsec String ParseState Value+parseArrayLiteral = ArrayLiteral <$> C.squares (C.commaSep parseValue)++parseObjectLiteral :: P.Parsec String ParseState Value+parseObjectLiteral = ObjectLiteral <$> C.braces (C.commaSep parseIdentifierAndValue)++parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)+parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)+ <*> (C.indented *> parseValue)++parseAbs :: P.Parsec String ParseState Value+parseAbs = do+ C.reservedOp "\\"+ args <- P.many1 (C.indented *> (Abs <$> (Left <$> P.try C.parseIdent <|> Right <$> parseBinderNoParens)))+ C.indented *> C.reservedOp "->"+ value <- parseValue+ return $ toFunction args value+ where+ toFunction :: [Value -> Value] -> Value -> Value+ toFunction args value = foldr ($) value args++parseVar :: P.Parsec String ParseState Value+parseVar = Var <$> C.parseQualified C.parseIdent++parseConstructor :: P.Parsec String ParseState Value+parseConstructor = Constructor <$> C.parseQualified C.properName++parseCase :: P.Parsec String ParseState Value+parseCase = Case <$> P.between (P.try (C.reserved "case")) (C.indented *> C.reserved "of") (return <$> parseValue)+ <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))++parseCaseAlternative :: P.Parsec String ParseState CaseAlternative+parseCaseAlternative = CaseAlternative <$> (return <$> parseBinder)+ <*> P.optionMaybe parseGuard+ <*> (C.indented *> C.reservedOp "->" *> parseValue)+ P.<?> "case alternative"++parseIfThenElse :: P.Parsec String ParseState Value+parseIfThenElse = IfThenElse <$> (P.try (C.reserved "if") *> C.indented *> parseValue)+ <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)+ <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)++parseLet :: P.Parsec String ParseState Value+parseLet = do+ C.reserved "let"+ C.indented+ ds <- C.mark $ P.many1 (C.same *> parseLocalDeclaration)+ C.indented+ C.reserved "in"+ result <- parseValue+ return $ Let ds result++parseValueAtom :: P.Parsec String ParseState Value+parseValueAtom = P.choice+ [ P.try parseNumericLiteral+ , P.try parseStringLiteral+ , P.try parseBooleanLiteral+ , parseArrayLiteral+ , P.try parseObjectLiteral+ , parseAbs+ , P.try parseConstructor+ , P.try parseVar+ , parseCase+ , parseIfThenElse+ , parseDo+ , parseLet+ , Parens <$> C.parens parseValue ]++parsePropertyUpdate :: P.Parsec String ParseState (String, Value)+parsePropertyUpdate = do+ name <- C.lexeme C.identifier+ _ <- C.lexeme $ C.indented *> P.char '='+ value <- C.indented *> parseValue+ return (name, value)++parseAccessor :: Value -> P.Parsec String ParseState Value+parseAccessor (Constructor _) = P.unexpected "constructor"+parseAccessor obj = P.try $ Accessor <$> (C.indented *> C.dot *> P.notFollowedBy C.opLetter *> C.indented *> C.identifier) <*> pure obj++parseDo :: P.Parsec String ParseState Value+parseDo = do+ C.reserved "do"+ C.indented+ Do <$> C.mark (P.many (C.same *> C.mark parseDoNotationElement))++parseDoNotationLet :: P.Parsec String ParseState DoNotationElement+parseDoNotationLet = DoNotationLet <$> (C.reserved "let" *> C.indented *> parseBinder)+ <*> (C.indented *> C.reservedOp "=" *> parseValue)++parseDoNotationBind :: P.Parsec String ParseState DoNotationElement+parseDoNotationBind = DoNotationBind <$> parseBinder <*> (C.indented *> C.reservedOp "<-" *> parseValue)++parseDoNotationElement :: P.Parsec String ParseState DoNotationElement+parseDoNotationElement = P.choice+ [ P.try parseDoNotationBind+ , parseDoNotationLet+ , P.try (DoNotationValue <$> parseValue) ]++-- |+-- Parse a value+--+parseValue :: P.Parsec String ParseState Value+parseValue =+ (P.buildExpressionParser operators+ . C.buildPostfixParser postfixTable2+ $ indexersAndAccessors) P.<?> "expression"+ where+ indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom+ postfixTable1 = [ parseAccessor+ , \v -> P.try $ flip ObjectUpdate <$> (C.indented *> C.braces (C.commaSep1 (C.indented *> parsePropertyUpdate))) <*> pure v ]+ postfixTable2 = [ \v -> P.try (flip App <$> (C.indented *> indexersAndAccessors)) <*> pure v+ , \v -> flip (TypedValue True) <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) <*> pure v+ ]+ operators = [ [ P.Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->+ return (BinaryNoParens ident))) P.AssocRight ]+ ]++parseStringBinder :: P.Parsec String ParseState Binder+parseStringBinder = StringBinder <$> C.stringLiteral++parseBooleanBinder :: P.Parsec String ParseState Binder+parseBooleanBinder = BooleanBinder <$> booleanLiteral++parseNumberBinder :: P.Parsec String ParseState Binder+parseNumberBinder = NumberBinder <$> C.integerOrFloat++parseVarBinder :: P.Parsec String ParseState Binder+parseVarBinder = VarBinder <$> C.parseIdent++parseNullaryConstructorBinder :: P.Parsec String ParseState Binder+parseNullaryConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> pure []++parseConstructorBinder :: P.Parsec String ParseState Binder+parseConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> many (C.indented *> parseBinderNoParens)++parseObjectBinder :: P.Parsec String ParseState Binder+parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep (C.indented *> parseIdentifierAndBinder))++parseArrayBinder :: P.Parsec String ParseState Binder+parseArrayBinder = C.squares $ ArrayBinder <$> C.commaSep (C.indented *> parseBinder)++parseNamedBinder :: P.Parsec String ParseState Binder+parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))+ <*> (C.indented *> parseBinder)++parseNullBinder :: P.Parsec String ParseState Binder+parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder++parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)+parseIdentifierAndBinder = do+ name <- C.lexeme C.identifier+ _ <- C.lexeme $ C.indented *> P.char '='+ binder <- C.indented *> parseBinder+ return (name, binder)++-- |+-- Parse a binder+--+parseBinder :: P.Parsec String ParseState Binder+parseBinder = P.buildExpressionParser operators parseBinderAtom P.<?> "expression"+ where+ operators = [ [ P.Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) P.AssocRight ] ]+ parseBinderAtom :: P.Parsec String ParseState Binder+ parseBinderAtom = P.choice (map P.try+ [ parseNullBinder+ , parseStringBinder+ , parseBooleanBinder+ , parseNumberBinder+ , parseNamedBinder+ , parseVarBinder+ , parseConstructorBinder+ , parseObjectBinder+ , parseArrayBinder+ , C.parens parseBinder ]) P.<?> "binder"++-- |+-- Parse a binder as it would appear in a top level declaration+--+parseBinderNoParens :: P.Parsec String ParseState Binder+parseBinderNoParens = P.choice (map P.try+ [ parseNullBinder+ , parseStringBinder+ , parseBooleanBinder+ , parseNumberBinder+ , parseNamedBinder+ , parseVarBinder+ , parseNullaryConstructorBinder+ , parseObjectBinder+ , parseArrayBinder+ , C.parens parseBinder ]) P.<?> "binder"+-- |+-- Parse a guard+--+parseGuard :: P.Parsec String ParseState Guard+parseGuard = C.indented *> C.pipe *> C.indented *> parseValue++
src/Language/PureScript/Parser/Types.hs view
@@ -49,7 +49,7 @@ parseFunction = parens $ P.try (lexeme (P.string "->")) >> return tyFunction parseObject :: P.Parsec String ParseState Type-parseObject = braces $ Object <$> parseRow False+parseObject = braces $ TypeApp tyObject <$> parseRow False parseTypeVariable :: P.Parsec String ParseState Type parseTypeVariable = do
− src/Language/PureScript/Parser/Values.hs
@@ -1,246 +0,0 @@------------------------------------------------------------------------------------ Module : Language.PureScript.Parser.Values--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |--- Parsers for values, statements, binders and guards-----------------------------------------------------------------------------------module Language.PureScript.Parser.Values (- parseValue,- parseGuard,- parseBinder,- parseBinderNoParens,-) where--import Control.Applicative--import Language.PureScript.Values-import Language.PureScript.Parser.State-import Language.PureScript.Parser.Types--import Text.Parsec.Expr--import qualified Language.PureScript.Parser.Common as C-import qualified Text.Parsec as P--booleanLiteral :: P.Parsec String ParseState Bool-booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)--parseNumericLiteral :: P.Parsec String ParseState Value-parseNumericLiteral = NumericLiteral <$> C.integerOrFloat--parseStringLiteral :: P.Parsec String ParseState Value-parseStringLiteral = StringLiteral <$> C.stringLiteral--parseBooleanLiteral :: P.Parsec String ParseState Value-parseBooleanLiteral = BooleanLiteral <$> booleanLiteral--parseArrayLiteral :: P.Parsec String ParseState Value-parseArrayLiteral = ArrayLiteral <$> C.squares (C.commaSep parseValue)--parseObjectLiteral :: P.Parsec String ParseState Value-parseObjectLiteral = ObjectLiteral <$> C.braces (C.commaSep parseIdentifierAndValue)--parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)-parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)- <*> (C.indented *> parseValue)--parseAbs :: P.Parsec String ParseState Value-parseAbs = do- C.reservedOp "\\"- args <- P.many1 (C.indented *> (Abs <$> (Left <$> P.try C.parseIdent <|> Right <$> parseBinderNoParens)))- C.indented *> C.reservedOp "->"- value <- parseValue- return $ toFunction args value- where- toFunction :: [Value -> Value] -> Value -> Value- toFunction args value = foldr ($) value args--parseVar :: P.Parsec String ParseState Value-parseVar = Var <$> C.parseQualified C.parseIdent--parseConstructor :: P.Parsec String ParseState Value-parseConstructor = Constructor <$> C.parseQualified C.properName--parseCase :: P.Parsec String ParseState Value-parseCase = Case <$> P.between (P.try (C.reserved "case")) (C.indented *> C.reserved "of") (return <$> parseValue)- <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))--parseCaseAlternative :: P.Parsec String ParseState CaseAlternative-parseCaseAlternative = CaseAlternative <$> (return <$> parseBinder)- <*> P.optionMaybe parseGuard- <*> (C.indented *> C.reservedOp "->" *> parseValue)- P.<?> "case alternative"--parseIfThenElse :: P.Parsec String ParseState Value-parseIfThenElse = IfThenElse <$> (P.try (C.reserved "if") *> C.indented *> parseValue)- <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)- <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)--parseLet :: P.Parsec String ParseState Value-parseLet = do- C.reserved "let"- C.indented- binder <- P.try (Right <$> ((,) <$> C.parseIdent <*> P.many (Left <$> P.try C.parseIdent <|> Right <$> parseBinderNoParens)))- <|> (Left <$> parseBinder)- C.indented- C.reservedOp "="- C.indented- value <- parseValue- C.indented- C.reserved "in"- result <- parseValue- return $ Let binder value result--parseValueAtom :: P.Parsec String ParseState Value-parseValueAtom = P.choice- [ P.try parseNumericLiteral- , P.try parseStringLiteral- , P.try parseBooleanLiteral- , parseArrayLiteral- , P.try parseObjectLiteral- , parseAbs- , P.try parseConstructor- , P.try parseVar- , parseCase- , parseIfThenElse- , parseDo- , parseLet- , Parens <$> C.parens parseValue ]--parsePropertyUpdate :: P.Parsec String ParseState (String, Value)-parsePropertyUpdate = do- name <- C.lexeme C.identifier- _ <- C.lexeme $ C.indented *> P.char '='- value <- C.indented *> parseValue- return (name, value)--parseAccessor :: Value -> P.Parsec String ParseState Value-parseAccessor (Constructor _) = P.unexpected "constructor"-parseAccessor obj = P.try $ Accessor <$> (C.indented *> C.dot *> P.notFollowedBy C.opLetter *> C.indented *> C.identifier) <*> pure obj--parseDo :: P.Parsec String ParseState Value-parseDo = do- C.reserved "do"- C.indented- Do <$> C.mark (P.many (C.same *> C.mark parseDoNotationElement))--parseDoNotationLet :: P.Parsec String ParseState DoNotationElement-parseDoNotationLet = DoNotationLet <$> (C.reserved "let" *> C.indented *> parseBinder)- <*> (C.indented *> C.reservedOp "=" *> parseValue)--parseDoNotationBind :: P.Parsec String ParseState DoNotationElement-parseDoNotationBind = DoNotationBind <$> parseBinder <*> (C.indented *> C.reservedOp "<-" *> parseValue)--parseDoNotationElement :: P.Parsec String ParseState DoNotationElement-parseDoNotationElement = P.choice- [ P.try parseDoNotationBind- , parseDoNotationLet- , P.try (DoNotationValue <$> parseValue) ]---- |--- Parse a value----parseValue :: P.Parsec String ParseState Value-parseValue =- (buildExpressionParser operators- . C.buildPostfixParser postfixTable2- $ indexersAndAccessors) P.<?> "expression"- where- indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom- postfixTable1 = [ parseAccessor- , \v -> P.try $ flip ObjectUpdate <$> (C.indented *> C.braces (C.commaSep1 (C.indented *> parsePropertyUpdate))) <*> pure v ]- postfixTable2 = [ \v -> P.try (flip App <$> (C.indented *> indexersAndAccessors)) <*> pure v- , \v -> flip (TypedValue True) <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) <*> pure v- ]- operators = [ [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->- return (BinaryNoParens ident))) AssocRight ]- ]--parseStringBinder :: P.Parsec String ParseState Binder-parseStringBinder = StringBinder <$> C.stringLiteral--parseBooleanBinder :: P.Parsec String ParseState Binder-parseBooleanBinder = BooleanBinder <$> booleanLiteral--parseNumberBinder :: P.Parsec String ParseState Binder-parseNumberBinder = NumberBinder <$> C.integerOrFloat--parseVarBinder :: P.Parsec String ParseState Binder-parseVarBinder = VarBinder <$> C.parseIdent--parseNullaryConstructorBinder :: P.Parsec String ParseState Binder-parseNullaryConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> pure []--parseConstructorBinder :: P.Parsec String ParseState Binder-parseConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> many (C.indented *> parseBinderNoParens)--parseObjectBinder :: P.Parsec String ParseState Binder-parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep (C.indented *> parseIdentifierAndBinder))--parseArrayBinder :: P.Parsec String ParseState Binder-parseArrayBinder = C.squares $ ArrayBinder <$> C.commaSep (C.indented *> parseBinder)--parseNamedBinder :: P.Parsec String ParseState Binder-parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))- <*> (C.indented *> parseBinder)--parseNullBinder :: P.Parsec String ParseState Binder-parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder--parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)-parseIdentifierAndBinder = do- name <- C.lexeme C.identifier- _ <- C.lexeme $ C.indented *> P.char '='- binder <- C.indented *> parseBinder- return (name, binder)---- |--- Parse a binder----parseBinder :: P.Parsec String ParseState Binder-parseBinder = buildExpressionParser operators parseBinderAtom P.<?> "expression"- where- operators = [ [ Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) AssocRight ] ]- parseBinderAtom :: P.Parsec String ParseState Binder- parseBinderAtom = P.choice (map P.try- [ parseNullBinder- , parseStringBinder- , parseBooleanBinder- , parseNumberBinder- , parseNamedBinder- , parseVarBinder- , parseConstructorBinder- , parseObjectBinder- , parseArrayBinder- , C.parens parseBinder ]) P.<?> "binder"---- |--- Parse a binder as it would appear in a top level declaration----parseBinderNoParens :: P.Parsec String ParseState Binder-parseBinderNoParens = P.choice (map P.try- [ parseNullBinder- , parseStringBinder- , parseBooleanBinder- , parseNumberBinder- , parseNamedBinder- , parseVarBinder- , parseNullaryConstructorBinder- , parseObjectBinder- , parseArrayBinder- , C.parens parseBinder ]) P.<?> "binder"--- |--- Parse a guard----parseGuard :: P.Parsec String ParseState Guard-parseGuard = C.indented *> C.pipe *> C.indented *> parseValue-
src/Language/PureScript/Pretty/Types.hs view
@@ -34,8 +34,8 @@ typeLiterals :: Pattern () Type String typeLiterals = mkPattern match where- match (Object row) = Just $ "{ " ++ prettyPrintRow row ++ " }" match (TypeVar var) = Just var+ match (PrettyPrintObject row) = Just $ "{ " ++ prettyPrintRow row ++ " }" match (PrettyPrintArray ty) = Just $ "[" ++ prettyPrintType ty ++ "]" match (TypeConstructor ctor) = Just $ show ctor match (TUnknown (Unknown u)) = Just $ 'u' : show u@@ -56,10 +56,7 @@ nameAndTypeToPs name ty = name ++ " :: " ++ prettyPrintType ty tailToPs :: Type -> String tailToPs REmpty = ""- tailToPs (TUnknown (Unknown u)) = " | u" ++ show u- tailToPs (TypeVar var) = " | " ++ var- tailToPs (Skolem s _) = " | s" ++ show s- tailToPs _ = error "Invalid row tail"+ tailToPs other = " | " ++ prettyPrintType other toList :: [(String, Type)] -> Type -> ([(String, Type)], Type) toList tys (RCons name ty row) = toList ((name, ty):tys) row toList tys r = (tys, r)@@ -81,6 +78,7 @@ where convert (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret convert (TypeApp a el) | a == tyArray = PrettyPrintArray el+ convert (TypeApp o r) | o == tyObject = PrettyPrintObject r convert other = other convertForAlls (ForAll ident ty _) = go [ident] ty where
src/Language/PureScript/Pretty/Values.hs view
@@ -24,7 +24,7 @@ import Control.PatternArrows import Language.PureScript.Types-import Language.PureScript.Values+import Language.PureScript.Declarations import Language.PureScript.Pretty.Common import Language.PureScript.Pretty.Types @@ -40,6 +40,7 @@ match (Constructor name) = Just $ show name match (Case values binders) = Just $ "case " ++ unwords (map prettyPrintValue values) ++ " of { " ++ intercalate " ; " (map prettyPrintCaseAlternative binders) ++ " }"+ match (Let _ val) = Just $ "let ... in " ++ prettyPrintValue val match (Var ident) = Just $ show ident match (Do els) = Just $ " do { " ++ intercalate "; " (map prettyPrintDoNotationElement els) ++ " }" match (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
src/Language/PureScript/Scope.hs view
@@ -24,7 +24,7 @@ import Data.List ((\\), nub) import Data.Generics (extQ, mkQ, everything) -import Language.PureScript.Values+import Language.PureScript.Declarations import Language.PureScript.Names import Language.PureScript.CodeGen.JS.AST
src/Language/PureScript/Sugar.hs view
@@ -16,7 +16,6 @@ module Language.PureScript.Sugar (desugar, module S) where import Control.Monad-import Control.Arrow ((>>>)) import Language.PureScript.Declarations @@ -26,14 +25,11 @@ import Language.PureScript.Sugar.TypeDeclarations as S import Language.PureScript.Sugar.BindingGroups as S import Language.PureScript.Sugar.TypeClasses as S-import Language.PureScript.Sugar.Let as S import Language.PureScript.Sugar.Names as S -- | -- The desugaring pipeline proceeds as follows: ----- * Desugar let bindings--- -- * Introduce type synonyms for type class dictionaries -- -- * Rebracket user-defined binary operators@@ -50,10 +46,9 @@ -- desugar :: [Module] -> Either String [Module] desugar = desugarDo- >=> desugarLetBindings- >>> desugarCasesModule+ >=> desugarCasesModule+ >=> desugarTypeDeclarationsModule >=> desugarImports >=> rebracket- >=> desugarTypeDeclarationsModule >=> desugarTypeClasses >=> createBindingGroupsModule
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -24,13 +24,13 @@ import Data.Data import Data.Graph import Data.Generics+import Data.Generics.Extras import Data.List (nub, intersect) import Data.Maybe (mapMaybe) import Control.Applicative ((<$>), (<*>), pure) import Language.PureScript.Declarations import Language.PureScript.Names-import Language.PureScript.Values import Language.PureScript.Types import Language.PureScript.Environment @@ -51,8 +51,8 @@ -- createBindingGroups :: ModuleName -> [Declaration] -> Either String [Declaration] createBindingGroups moduleName ds = do- let values = filter isValueDecl ds- dataDecls = filter isDataDecl ds+ values <- mapM (createBindingGroupsForValue moduleName) $ filter isValueDecl ds+ let dataDecls = filter isDataDecl ds allProperNames = map getProperName dataDecls dataVerts = map (\d -> (d, getProperName d, usedProperNames moduleName d `intersect` allProperNames)) dataDecls dataBindingGroupDecls <- mapM toDataBindingGroup $ stronglyConnComp dataVerts@@ -68,15 +68,25 @@ filter isExternDecl ds ++ bindingGroupDecls +createBindingGroupsForValue :: ModuleName -> Declaration -> Either String Declaration+createBindingGroupsForValue moduleName = everywhereM' (mkM go)+ where+ go (Let ds val) = Let <$> createBindingGroups moduleName ds <*> pure val+ go other = return other+ -- | -- Collapse all binding groups to individual declarations -- collapseBindingGroups :: [Declaration] -> [Declaration]-collapseBindingGroups = concatMap go+collapseBindingGroups = everywhere (mkT collapseBindingGroupsForValue) . concatMap go where go (DataBindingGroupDeclaration ds) = ds go (BindingGroupDeclaration ds) = map (\(ident, nameKind, val) -> ValueDeclaration ident nameKind [] Nothing val) ds go other = [other]++collapseBindingGroupsForValue :: Value -> Value+collapseBindingGroupsForValue (Let ds val) = Let (collapseBindingGroups ds) val+collapseBindingGroupsForValue other = other usedIdents :: (Data d) => ModuleName -> d -> [Ident] usedIdents moduleName = nub . everything (++) (mkQ [] usedNames)
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -20,14 +20,14 @@ ) where import Data.List (groupBy)-import Data.Generics (mkT, everywhere)+import Data.Generics (mkM, mkT, everywhere)+import Data.Generics.Extras import Control.Applicative import Control.Monad ((<=<), forM, join, unless) import Control.Monad.Error.Class import Language.PureScript.Names-import Language.PureScript.Values import Language.PureScript.Declarations import Language.PureScript.Scope import Language.PureScript.Environment@@ -57,6 +57,11 @@ desugarRest :: [Declaration] -> Either String [Declaration] desugarRest (TypeInstanceDeclaration name constraints className tys ds : rest) = (:) <$> (TypeInstanceDeclaration name constraints className tys <$> desugarCases ds) <*> desugarRest rest+ desugarRest (ValueDeclaration name nameKind bs g val : rest) = do+ (:) <$> (ValueDeclaration name nameKind bs g <$> everywhereM' (mkM go) val) <*> desugarRest rest+ where+ go (Let ds val') = Let <$> desugarCases ds <*> pure val'+ go other = return other desugarRest (d : ds) = (:) d <$> desugarRest ds desugarRest [] = pure []
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -21,9 +21,9 @@ import Data.Data import Data.Generics -import Language.PureScript.Values import Language.PureScript.Names import Language.PureScript.Scope+import Language.PureScript.Declarations import qualified Language.PureScript.Constants as C
− src/Language/PureScript/Sugar/Let.hs
@@ -1,34 +0,0 @@------------------------------------------------------------------------------------ Module : Language.PureScript.Sugar.Let--- Copyright : (c) Phil Freeman 2014--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |--- This module implements the desugaring pass which turns let bindings into function applications.-----------------------------------------------------------------------------------module Language.PureScript.Sugar.Let (- desugarLetBindings-) where--import Data.Generics (mkT, everywhere)--import Language.PureScript.Values-import Language.PureScript.Declarations---- |--- Turn let bindings into function applications----desugarLetBindings :: [Module] -> [Module]-desugarLetBindings = everywhere (mkT go)- where- go (Let (Left (VarBinder ident)) value result) = App (Abs (Left ident) result) value- go (Let (Left binder) value result) = Case [value] [CaseAlternative [binder] Nothing result]- go (Let (Right (ident, binders)) value result) = App (Abs (Left ident) result) (foldr Abs value binders)- go other = other
src/Language/PureScript/Sugar/Names.hs view
@@ -16,6 +16,7 @@ desugarImports ) where +import Data.Data import Data.Maybe (fromMaybe, isJust) import Data.Generics (extM, mkM, everywhereM) import Data.Generics.Extras (mkS, extS, everywhereWithContextM')@@ -28,7 +29,6 @@ import Language.PureScript.Declarations import Language.PureScript.Names import Language.PureScript.Types-import Language.PureScript.Values import Language.PureScript.Environment -- |@@ -134,10 +134,9 @@ -- desugarImports :: [Module] -> Either String [Module] desugarImports modules = do- let modules' = importPrelude `map` modules- unfilteredExports <- findExports modules'- exports <- foldM filterModuleExports unfilteredExports modules'- mapM (renameInModule' unfilteredExports exports) modules'+ unfilteredExports <- findExports modules+ exports <- foldM filterModuleExports unfilteredExports modules+ mapM (renameInModule' unfilteredExports exports) modules where -- Filters the exports for a module in the global exports environment so that only explicitly@@ -157,23 +156,16 @@ renameInModule imports env (elaborateExports exps m) -- |--- Add an import declaration for the Prelude to a module if it does not already explicitly import--- it.+-- Rethrow an error with an extra message line prepended ---importPrelude :: Module -> Module-importPrelude m@(Module mn decls exps) =- if isPreludeImport `any` decls then m- else Module mn (preludeImport : decls) exps- where- isPreludeImport (ImportDeclaration (ModuleName [ProperName "Prelude"]) _ _) = True- isPreludeImport _ = False- preludeImport = ImportDeclaration (ModuleName [ProperName "Prelude"]) Nothing Nothing+rethrow :: String -> Either String a -> Either String a+rethrow msg = flip catchError $ \e -> throwError (msg ++ ":\n" ++ e) -- |--- Rethrow an error with the name of the current module in the case of a failure+-- Rethrow an error with details of the current module prepended to the message -- rethrowForModule :: Module -> Either String a -> Either String a-rethrowForModule (Module mn _ _) = flip catchError $ \e -> throwError ("Error in module '" ++ show mn ++ "':\n" ++ e)+rethrowForModule (Module mn _ _) = rethrow $ "Error in module '" ++ show mn ++ "'" -- | -- Make all exports for a module explicit. This may still effect modules that have an exports list,@@ -191,19 +183,25 @@ -- renameInModule :: ImportEnvironment -> ExportEnvironment -> Module -> Either String Module renameInModule imports exports (Module mn decls exps) =- Module mn <$> (mapM updateDecl decls >>= everywhereM (mkM updateType `extM` updateValue `extM` updateBinder `extM` updateVars)) <*> pure exps+ Module mn <$> mapM go decls <*> pure exps where- updateDecl (TypeInstanceDeclaration name cs cn ts ds) =- TypeInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> pure ts <*> pure ds- updateDecl (ExternInstanceDeclaration name cs cn ts) =- ExternInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> pure ts- updateDecl d = return d-- updateVars :: Declaration -> Either String Declaration- updateVars (ValueDeclaration name nameKind [] Nothing val) =- ValueDeclaration name nameKind [] Nothing <$> everywhereWithContextM' [] (mkS bindFunctionArgs `extS` bindBinders) val+ go (DataDeclaration name args dctors) =+ rethrowFor "data declaration" name $ DataDeclaration <$> pure name <*> pure args <*> updateAll dctors+ go (DataBindingGroupDeclaration decls') =+ DataBindingGroupDeclaration <$> mapM go decls'+ go (TypeSynonymDeclaration name ps ty) =+ rethrowFor "type synonym" name $ TypeSynonymDeclaration <$> pure name <*> pure ps <*> updateType' ty+ go (TypeInstanceDeclaration name cs cn ts ds) =+ TypeInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> updateType' ts <*> mapM go ds+ go (ExternInstanceDeclaration name cs cn ts) =+ ExternInstanceDeclaration name <$> updateConstraints cs <*> updateClassName cn <*> updateType' ts+ go (ValueDeclaration name nameKind [] Nothing val) = do+ val' <- everywhereWithContextM' [] (mkS bindFunctionArgs `extS` bindBinders) val+ rethrowFor "declaration" name $ ValueDeclaration name nameKind [] Nothing <$> updateAll val' where bindFunctionArgs bound (Abs (Left arg) val') = return (arg : bound, Abs (Left arg) val')+ bindFunctionArgs bound (Let ds val') = let args = map letBoundVariable ds in+ return (args ++ bound, Let ds val') bindFunctionArgs bound (Var name'@(Qualified Nothing ident)) | ident `notElem` bound = (,) bound <$> (Var <$> updateValueName name') bindFunctionArgs bound (Var name'@(Qualified (Just _) _)) =@@ -215,16 +213,37 @@ bindFunctionArgs bound other = return (bound, other) bindBinders :: [Ident] -> CaseAlternative -> Either String ([Ident], CaseAlternative) bindBinders bound c@(CaseAlternative bs _ _) = return (binderNames bs ++ bound, c)- updateVars (ValueDeclaration name _ _ _ _) = error $ "Binders should have been desugared in " ++ show name- updateVars other = return other++ letBoundVariable :: Declaration -> Ident+ letBoundVariable (ValueDeclaration ident _ _ _ _) = ident+ letBoundVariable _ = error "Invalid argument to letBoundVariable"+ go (ValueDeclaration name _ _ _ _) = error $ "Binders should have been desugared in " ++ show name+ go (ExternDeclaration fit name js ty) =+ rethrowFor "declaration" name $ ExternDeclaration <$> pure fit <*> pure name <*> pure js <*> updateType' ty+ go (BindingGroupDeclaration decls') = do+ BindingGroupDeclaration <$> mapM go' decls'+ where go' = \(name, nk, value) -> rethrowFor "declaration" name $ (,,) <$> pure name <*> pure nk <*> updateAll value+ go d = updateAll d++ rethrowFor :: (Show a) => String -> a -> Either String b -> Either String b+ rethrowFor what name = rethrow $ "Error in " ++ what ++ " '" ++ show name ++ "'"++ updateAll :: Data d => d -> Either String d+ updateAll = everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)+ updateValue (Constructor name) = Constructor <$> updateDataConstructorName name updateValue v = return v+ updateBinder (ConstructorBinder name b) = ConstructorBinder <$> updateDataConstructorName name <*> pure b updateBinder v = return v+ updateType (TypeConstructor name) = TypeConstructor <$> updateTypeName name updateType (SaturatedTypeSynonym name tys) = SaturatedTypeSynonym <$> updateTypeName name <*> mapM updateType tys updateType (ConstrainedType cs t) = ConstrainedType <$> updateConstraints cs <*> pure t updateType t = return t+ updateType' :: Data d => d -> Either String d+ updateType' = everywhereM (mkM updateType)+ updateConstraints = mapM (\(name, ts) -> (,) <$> updateClassName name <*> pure ts) updateTypeName = update "type" importedTypes (\mes -> isJust . (`lookup` (exportedTypes mes)))
src/Language/PureScript/Sugar/Operators.hs view
@@ -25,7 +25,6 @@ import Language.PureScript.Names import Language.PureScript.Declarations-import Language.PureScript.Values import Control.Applicative import Control.Monad.State@@ -107,6 +106,7 @@ toAssoc :: Associativity -> P.Assoc toAssoc Infixl = P.AssocLeft toAssoc Infixr = P.AssocRight+toAssoc Infix = P.AssocNone token :: (P.Stream s Identity t, Show t) => (t -> Maybe a) -> P.Parsec s u a token = P.token show (const (P.initialPos ""))
src/Language/PureScript/Sugar/TypeClasses.hs view
@@ -22,7 +22,6 @@ import Language.PureScript.Declarations import Language.PureScript.Names import Language.PureScript.Types-import Language.PureScript.Values import Language.PureScript.CodeGen.JS.AST import Language.PureScript.Sugar.CaseDeclarations import Language.PureScript.Environment@@ -108,7 +107,7 @@ typeClassDictionaryDeclaration :: ProperName -> [String] -> [Declaration] -> Declaration typeClassDictionaryDeclaration name args members =- TypeSynonymDeclaration name args (Object $ rowFromList (map memberToNameAndType members, REmpty))+ TypeSynonymDeclaration name args (TypeApp tyObject $ rowFromList (map memberToNameAndType members, REmpty)) typeClassMemberToDictionaryAccessor :: ModuleName -> ProperName -> [String] -> Declaration -> Declaration typeClassMemberToDictionaryAccessor mn name args (TypeDeclaration ident ty) =@@ -134,6 +133,9 @@ foldr (function . (\(pn, tys') -> foldl TypeApp (TypeConstructor pn) tys')) (foldl TypeApp (TypeConstructor className) tys) deps)) ) where+ unit :: Type+ unit = TypeApp tyObject REmpty+ memberToNameAndValue :: [(String, Type)] -> Declaration -> Desugar (String, Value) memberToNameAndValue tys' (ValueDeclaration ident _ _ _ _) = do memberType <- lift . maybe (Left "Type class member type not found") Right $ lookup (identToJs ident) tys'
src/Language/PureScript/Sugar/TypeDeclarations.hs view
@@ -19,12 +19,14 @@ desugarTypeDeclarationsModule ) where +import Data.Generics (mkM)+import Data.Generics.Extras+ import Control.Applicative import Control.Monad.Error.Class import Control.Monad (forM) import Language.PureScript.Declarations-import Language.PureScript.Values -- | -- Replace all top level type declarations in a module with type annotations@@ -39,5 +41,10 @@ desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' nameKind [] Nothing val : rest) | name == name' = desugarTypeDeclarations (ValueDeclaration name nameKind [] Nothing (TypedValue True val ty) : rest) desugarTypeDeclarations (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name+desugarTypeDeclarations (ValueDeclaration name nameKind bs g val : rest) = do+ (:) <$> (ValueDeclaration name nameKind bs g <$> everywhereM' (mkM go) val) <*> desugarTypeDeclarations rest+ where+ go (Let ds val') = Let <$> desugarTypeDeclarations ds <*> pure val'+ go other = return other desugarTypeDeclarations (d:ds) = (:) d <$> desugarTypeDeclarations ds desugarTypeDeclarations [] = return []
src/Language/PureScript/TypeChecker.hs view
@@ -32,9 +32,9 @@ import Language.PureScript.Types import Language.PureScript.Names-import Language.PureScript.Values import Language.PureScript.Kinds import Language.PureScript.Declarations+import Language.PureScript.TypeClassDictionaries import Language.PureScript.Environment import Language.PureScript.Pretty.Types @@ -107,7 +107,7 @@ typeCheckAll _ _ [] = return [] typeCheckAll mainModuleName moduleName (d@(DataDeclaration name args dctors) : rest) = do rethrow (("Error in type constructor " ++ show name ++ ":\n") ++) $ do- ctorKind <- kindsOf moduleName name args (concatMap snd dctors)+ ctorKind <- kindsOf True moduleName name args (concatMap snd dctors) addDataType moduleName name args dctors ctorKind ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds@@ -129,7 +129,7 @@ toDataDecl _ = Nothing typeCheckAll mainModuleName moduleName (d@(TypeSynonymDeclaration name args ty) : rest) = do rethrow (("Error in type synonym " ++ show name ++ ":\n") ++) $ do- kind <- kindsOf moduleName name args [ty]+ kind <- kindsOf False moduleName name args [ty] addTypeSynonym moduleName name args ty kind ds <- typeCheckAll mainModuleName moduleName rest return $ d : ds
src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -67,13 +67,13 @@ -- | -- Infer the kind of a type constructor with a collection of arguments and a collection of associated data constructors ---kindsOf :: ModuleName -> ProperName -> [String] -> [Type] -> Check Kind-kindsOf moduleName name args ts = fmap tidyUp . liftUnify $ do+kindsOf :: Bool -> ModuleName -> ProperName -> [String] -> [Type] -> Check Kind+kindsOf isData moduleName name args ts = fmap tidyUp . liftUnify $ do tyCon <- fresh kargs <- replicateM (length args) fresh let dict = (name, tyCon) : zipWith (\arg kind -> (arg, kind)) (map ProperName args) kargs bindLocalTypeVariables moduleName dict $- solveTypes ts kargs tyCon+ solveTypes isData ts kargs tyCon where tidyUp (k, sub) = starIfUnknown $ sub $? k @@ -92,12 +92,12 @@ kargs <- replicateM (length args) fresh let argDict = zip (map ProperName args) kargs bindLocalTypeVariables moduleName argDict $- solveTypes ts kargs tyCon) tyCons tys+ solveTypes True ts kargs tyCon) tyCons tys syn_ks <- zipWithM (\synVar (_, args, ty) -> do kargs <- replicateM (length args) fresh let argDict = zip (map ProperName args) kargs bindLocalTypeVariables moduleName argDict $- solveTypes [ty] kargs synVar) synVars syns+ solveTypes False [ty] kargs synVar) synVars syns return (syn_ks, data_ks) where tidyUp ((ks1, ks2), sub) = (map (starIfUnknown . (sub $?)) ks1, map (starIfUnknown . (sub $?)) ks2)@@ -105,11 +105,14 @@ -- | -- Solve the set of kind constraints associated with the data constructors for a type constructor ---solveTypes :: [Type] -> [Kind] -> Kind -> UnifyT Kind Check Kind-solveTypes ts kargs tyCon = do+solveTypes :: Bool -> [Type] -> [Kind] -> Kind -> UnifyT Kind Check Kind+solveTypes isData ts kargs tyCon = do ks <- mapM infer ts- tyCon =?= foldr FunKind Star kargs- forM_ ks $ \k -> k =?= Star+ when isData $ do+ tyCon =?= foldr FunKind Star kargs+ forM_ ks $ \k -> k =?= Star+ when (not isData) $ do+ tyCon =?= foldr FunKind (head ks) kargs return tyCon -- |@@ -117,6 +120,7 @@ -- starIfUnknown :: Kind -> Kind starIfUnknown (KUnknown _) = Star+starIfUnknown (Row k) = Row (starIfUnknown k) starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2) starIfUnknown k = k @@ -124,10 +128,6 @@ -- Infer a kind for a type -- infer :: Type -> UnifyT Kind Check Kind-infer (Object row) = do- k <- infer row- k =?= Row Star- return Star infer (TypeVar v) = do Just moduleName <- checkCurrentModule <$> get UnifyT . lift $ lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -20,9 +20,9 @@ import Language.PureScript.Types import Language.PureScript.Kinds-import Language.PureScript.Values import Language.PureScript.Names import Language.PureScript.Environment+import Language.PureScript.TypeClassDictionaries import Data.Maybe
src/Language/PureScript/TypeChecker/Types.hs view
@@ -48,10 +48,11 @@ something, everywhere, mkQ) import Data.Generics.Extras -import Language.PureScript.Values+import Language.PureScript.Declarations import Language.PureScript.Types import Language.PureScript.Kinds import Language.PureScript.Names+import Language.PureScript.TypeClassDictionaries import Language.PureScript.TypeChecker.Monad import Language.PureScript.TypeChecker.Kinds import Language.PureScript.TypeChecker.Synonyms@@ -106,7 +107,6 @@ sk `unifyTypes` ty2 unifyTypes' ForAll{} _ = throwError "Skolem variable scope is unspecified" unifyTypes' ty f@ForAll{} = f `unifyTypes` ty- unifyTypes' (Object row1) (Object row2) = row1 =?= row2 unifyTypes' (TypeVar v1) (TypeVar v2) | v1 == v2 = return () unifyTypes' (TypeConstructor c1) (TypeConstructor c2) = guardWith ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".") (c1 == c2)@@ -163,48 +163,15 @@ typesOf :: Maybe ModuleName -> ModuleName -> [(Ident, Value)] -> Check [(Ident, (Value, Type))] typesOf mainModuleName moduleName vals = do tys <- fmap tidyUp . liftUnify $ do- let- -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed- es = map isTyped vals- -- Filter the typed and untyped declarations- typed = filter (isJust . snd . snd) es- untyped = filter (isNothing . snd . snd) es- -- Make a map of names to typed declarations- typedDict = map (\(ident, (_, Just (ty, _))) -> (ident, ty)) typed- -- Create fresh unification variables for the types of untyped declarations- untypedNames <- replicateM (length untyped) fresh- let- -- Make a map of names to the unification variables of untyped declarations- untypedDict = zip (map fst untyped) untypedNames- -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking- dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable))) $ typedDict ++ untypedDict)- forM es $ \e@(_, (val, _)) -> do- -- If the declaration is a function, it has access to other values in the binding group.- -- If not, the generated code might fail at runtime since those values might be undefined.- let dict' = if isFunction val then dict else M.empty- triple@(_, (_, ty)) <- case e of- -- Typed declarations- (ident, (val', Just (ty, checkType))) -> do- -- Kind check- kind <- liftCheck $ kindOf moduleName ty- guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star- -- Check the type with the new names in scope- ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty- val'' <- bindNames dict' $ if checkType- then TypedValue True <$> check val' ty' <*> pure ty'- else return (TypedValue False val' ty')- return (ident, (val'', ty'))- -- Untyped declarations- (ident, (val', Nothing)) -> do- -- Infer the type with the new names in scope- TypedValue _ val'' ty <- bindNames dict' $ infer val'- ty =?= fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)- return (ident, (TypedValue True val'' ty, ty))+ (es, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName vals+ forM es $ \e -> do+ triple@(_, (_, ty)) <- typeForBindingGroupElement moduleName e dict untypedDict -- If --main is enabled, need to check that `main` has type Eff eff a for some eff, a when (Just moduleName == mainModuleName && fst e == Ident C.main) $ do [eff, a] <- replicateM 2 fresh ty =?= TypeApp (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Control", ProperName "Monad", ProperName "Eff"])) (ProperName "Eff"))) eff) a return triple+ forM tys $ \(ident, (val, ty)) -> do -- Replace type class dictionary placeholders with actual dictionaries val' <- replaceTypeClassDictionaries moduleName val@@ -219,6 +186,51 @@ -- Apply the substitution that was returned from runUnify to both types and (type-annotated) values tidyUp (ts, sub) = map (\(i, (val, ty)) -> (i, (overTypes (sub $?) val, sub $? ty))) ts +typeDictionaryForBindingGroup :: ModuleName -> [(Ident, Value)] -> UnifyT Type Check ([(Ident, (Value, Maybe (Type, Bool)))], M.Map (ModuleName, Ident) (Type, NameKind), [(Ident, Type)])+typeDictionaryForBindingGroup moduleName vals = do+ let+ -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed+ es = map isTyped vals+ -- Filter the typed and untyped declarations+ typed = filter (isJust . snd . snd) es+ untyped = filter (isNothing . snd . snd) es+ -- Make a map of names to typed declarations+ typedDict = map (\(ident, (_, Just (ty, _))) -> (ident, ty)) typed++ -- Create fresh unification variables for the types of untyped declarations+ untypedNames <- replicateM (length untyped) fresh++ let+ -- Make a map of names to the unification variables of untyped declarations+ untypedDict = zip (map fst untyped) untypedNames+ -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking+ dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable))) $ typedDict ++ untypedDict)+ return (es, dict, untypedDict)++typeForBindingGroupElement :: ModuleName -> (Ident, (Value, Maybe (Type, Bool))) -> M.Map (ModuleName, Ident) (Type, NameKind) -> [(Ident, Type)] -> UnifyT Type Check (Ident, (Value, Type))+typeForBindingGroupElement moduleName e@(_, (val, _)) dict untypedDict = do+ -- If the declaration is a function, it has access to other values in the binding group.+ -- If not, the generated code might fail at runtime since those values might be undefined.+ let dict' = if isFunction val then dict else M.empty+ case e of+ -- Typed declarations+ (ident, (val', Just (ty, checkType))) -> do+ -- Kind check+ kind <- liftCheck $ kindOf moduleName ty+ guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+ -- Check the type with the new names in scope+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty+ val'' <- bindNames dict' $ if checkType+ then TypedValue True <$> check val' ty' <*> pure ty'+ else return (TypedValue False val' ty')+ return (ident, (val'', ty'))+ -- Untyped declarations+ (ident, (val', Nothing)) -> do+ -- Infer the type with the new names in scope+ TypedValue _ val'' ty <- bindNames dict' $ infer val'+ ty =?= fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)+ return (ident, (TypedValue True val'' ty, ty))+ -- | -- Check if a value introduces a function --@@ -462,6 +474,12 @@ env <- getEnv either throwError return $ expandTypeSynonym' env name args +expandAllTypeSynonyms :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => Type -> m Type+expandAllTypeSynonyms = everywhereM' (mkM go)+ where+ go (SaturatedTypeSynonym name args) = expandTypeSynonym name args+ go other = return other+ -- | -- Ensure a set of property names and value does not contain duplicate labels --@@ -490,7 +508,7 @@ ensureNoDuplicateProperties ps ts <- mapM (infer . snd) ps let fields = zipWith (\name (TypedValue _ _ t) -> (name, t)) (map fst ps) ts- ty = Object $ rowFromList (fields, REmpty)+ ty = TypeApp tyObject $ rowFromList (fields, REmpty) return $ TypedValue True (ObjectLiteral (zip (map fst ps) ts)) ty infer' (ObjectUpdate o ps) = do ensureNoDuplicateProperties ps@@ -498,9 +516,9 @@ newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> mapM (infer . snd) ps let newTys = map (\(name, TypedValue _ _ ty) -> (name, ty)) newVals oldTys <- zip (map fst ps) <$> replicateM (length ps) fresh- let oldTy = Object $ rowFromList (oldTys, row)+ let oldTy = TypeApp tyObject $ rowFromList (oldTys, row) o' <- TypedValue True <$> check o oldTy <*> pure oldTy- return $ TypedValue True (ObjectUpdate o' newVals) $ Object $ rowFromList (newTys, row)+ return $ TypedValue True (ObjectUpdate o' newVals) $ TypeApp tyObject $ rowFromList (newTys, row) infer' (Accessor prop val) = do typed@(TypedValue _ _ objTy) <- infer val propTy <- inferProperty objTy prop@@ -508,7 +526,7 @@ Nothing -> do field <- fresh rest <- fresh- _ <- subsumes Nothing objTy (Object (RCons prop field rest))+ _ <- subsumes Nothing objTy (TypeApp tyObject (RCons prop field rest)) return $ TypedValue True (Accessor prop typed) field Just ty -> return $ TypedValue True (Accessor prop typed) ty infer' (Abs (Left arg) ret) = do@@ -547,6 +565,9 @@ v3@(TypedValue _ _ t3) <- infer el t2 =?= t3 return $ TypedValue True (IfThenElse cond' v2 v3) t2+infer' (Let ds val) = do+ (ds', val'@(TypedValue _ _ valTy)) <- inferLetBinding [] ds val infer+ return $ TypedValue True (Let ds' val') valTy infer' (TypedValue checkType val ty) = do Just moduleName <- checkCurrentModule <$> get kind <- liftCheck $ kindOf moduleName ty@@ -556,11 +577,28 @@ return $ TypedValue True val' ty' infer' _ = error "Invalid argument to infer" +inferLetBinding :: [Declaration] -> [Declaration] -> Value -> (Value -> UnifyT Type Check Value) -> UnifyT Type Check ([Declaration], Value)+inferLetBinding seen [] ret j = (,) seen <$> j ret+inferLetBinding seen (ValueDeclaration ident nameKind [] Nothing val : rest) ret j = do+ valTy <- fresh+ Just moduleName <- checkCurrentModule <$> get+ TypedValue _ val' valTy' <- bindNames (M.singleton (moduleName, ident) (valTy, nameKind)) $ infer val+ valTy =?= valTy'+ bindNames (M.singleton (moduleName, ident) (valTy', nameKind)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] Nothing val']) rest ret j+inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do+ Just moduleName <- checkCurrentModule <$> get+ (es, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName (map (\(i, _, v) -> (i, v)) ds)+ ds' <- forM es $ \e -> do+ (ident, (val', _)) <- typeForBindingGroupElement moduleName e dict untypedDict+ return $ (ident, LocalVariable, val')+ bindNames dict $ inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j+inferLetBinding _ _ _ _ = error "Invalid argument to fromValueDeclaration"+ -- | -- Infer the type of a property inside a record with a given type -- inferProperty :: Type -> String -> UnifyT Type Check (Maybe Type)-inferProperty (Object row) prop = do+inferProperty (TypeApp obj row) prop | obj == tyObject = do let (props, _) = rowToList row return $ lookup prop props inferProperty (SaturatedTypeSynonym name args) prop = do@@ -599,7 +637,7 @@ row <- fresh rest <- fresh m1 <- inferRowProperties row rest props- val =?= Object row+ val =?= TypeApp tyObject row return m1 where inferRowProperties :: Type -> Type -> [(String, Binder)] -> UnifyT Type Check (M.Map Ident Type)@@ -703,8 +741,7 @@ return $ TypedValue True (foldr (Abs . Left) val' dictNames) t check' val (SaturatedTypeSynonym name args) = do ty <- introduceSkolemScope <=< expandTypeSynonym name $ args- val' <- check val ty- return $ TypedValue True val' ty+ check val ty check' val u@(TUnknown _) = do val'@(TypedValue _ _ ty) <- infer val -- Don't unify an unknown with an inferred polytype@@ -759,22 +796,22 @@ th' <- check th ty el' <- check el ty return $ TypedValue True (IfThenElse cond' th' el') ty-check' (ObjectLiteral ps) t@(Object row) = do+check' (ObjectLiteral ps) t@(TypeApp obj row) | obj == tyObject = do ensureNoDuplicateProperties ps ps' <- checkProperties ps row False return $ TypedValue True (ObjectLiteral ps') t-check' (ObjectUpdate obj ps) t@(Object row) = do+check' (ObjectUpdate obj ps) t@(TypeApp o row) | o == tyObject = do ensureNoDuplicateProperties ps us <- zip (map fst ps) <$> replicateM (length ps) fresh let (propsToCheck, rest) = rowToList row propsToRemove = map fst ps remainingProps = filter (\(p, _) -> p `notElem` propsToRemove) propsToCheck- obj' <- check obj (Object (rowFromList (us ++ remainingProps, rest)))+ obj' <- check obj (TypeApp tyObject (rowFromList (us ++ remainingProps, rest))) ps' <- checkProperties ps row True return $ TypedValue True (ObjectUpdate obj' ps') t check' (Accessor prop val) ty = do rest <- fresh- val' <- check val (Object (RCons prop ty rest))+ val' <- check val (TypeApp tyObject (RCons prop ty rest)) return $ TypedValue True (Accessor prop val') ty check' (Constructor c) ty = do env <- getEnv@@ -784,8 +821,19 @@ repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1 _ <- subsumes Nothing repl ty return $ TypedValue True (Constructor c) ty+check' (Let ds val) ty = do+ (ds', val') <- inferLetBinding [] ds val (flip check ty)+ return $ TypedValue True (Let ds' val') ty+check' val ty | containsTypeSynonyms ty = do+ ty' <- introduceSkolemScope <=< expandAllTypeSynonyms $ ty+ check val ty' check' val ty = throwError $ prettyPrintValue val ++ " does not have type " ++ prettyPrintType ty +containsTypeSynonyms :: Type -> Bool+containsTypeSynonyms = everything (||) (mkQ False go) where+ go (SaturatedTypeSynonym _ _) = True+ go _ = False+ -- | -- Check the type of a collection of named record fields --@@ -818,7 +866,7 @@ v' <- check v ty ps'' <- go ps' (delete (p, ty) ts) r return $ (p, v') : ps''- go _ _ _ = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have type " ++ prettyPrintType (Object row)+ go _ _ _ = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have type " ++ prettyPrintType (TypeApp tyObject row) -- | -- Check the type of a function application, rethrowing errors to provide a better error message@@ -903,7 +951,7 @@ dicts <- getTypeClassDictionaries _ <- subsumes' Nothing ty1 ty2 return . Just $ foldl App val (map (flip TypeClassDictionary dicts) constraints)-subsumes' val (Object r1) (Object r2) = do+subsumes' val (TypeApp f1 r1) (TypeApp f2 r2) | f1 == tyObject && f2 == tyObject = do let (ts1, r1') = rowToList r1 (ts2, r2') = rowToList r2@@ -923,7 +971,7 @@ | otherwise = do rest <- fresh r1' =?= RCons p2 ty2 rest go ((p1, ty1) : ts1) ts2 rest r2'-subsumes' val ty1 ty2@(Object _) = subsumes val ty2 ty1+subsumes' val ty1 ty2@(TypeApp obj _) | obj == tyObject = subsumes val ty2 ty1 subsumes' val ty1 ty2 = do ty1 =?= ty2 return val
+ src/Language/PureScript/TypeClassDictionaries.hs view
@@ -0,0 +1,62 @@+-----------------------------------------------------------------------------+--+-- Module : Language.PureScript.TypeClassDictionaries+-- Copyright : (c) 2014 Phil Freeman+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}++module Language.PureScript.TypeClassDictionaries where++import Data.Data++import Language.PureScript.Names+import Language.PureScript.Types++-- |+-- Data representing a type class dictionary which is in scope+--+data TypeClassDictionaryInScope+ = TypeClassDictionaryInScope {+ -- |+ -- The identifier with which the dictionary can be accessed at runtime+ --+ tcdName :: Qualified Ident+ -- |+ -- The name of the type class to which this type class instance applies+ --+ , tcdClassName :: Qualified ProperName+ -- |+ -- The types to which this type class instance applies+ --+ , tcdInstanceTypes :: [Type]+ -- |+ -- Type class dependencies which must be satisfied to construct this dictionary+ --+ , tcdDependencies :: Maybe [(Qualified ProperName, [Type])]+ -- |+ -- The type of this dictionary+ --+ , tcdType :: TypeClassDictionaryType+ } deriving (Show, Data, Typeable)++-- |+-- The type of a type class dictionary+--+data TypeClassDictionaryType+ -- |+ -- A regular type class dictionary+ --+ = TCDRegular+ -- |+ -- A type class dictionary which is an alias for an imported dictionary from another module+ --+ | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable)
src/Language/PureScript/Types.hs view
@@ -40,10 +40,6 @@ -- = TUnknown Unknown -- |- -- Javascript numbers- --- | Object Type- -- | -- A named type variable -- | TypeVar String@@ -90,6 +86,10 @@ -- | -- A placeholder used in pretty printing --+ | PrettyPrintObject Type+ -- |+ -- A placeholder used in pretty printing+ -- | PrettyPrintForAll [String] Type deriving (Show, Eq, Data, Typeable) -- |@@ -121,12 +121,6 @@ mkForAll args ty = foldl (\t arg -> ForAll arg t Nothing) ty args -- |--- The empty record type----unit :: Type-unit = Object REmpty---- | -- Replace a type variable, taking into account variable shadowing -- replaceTypeVars :: String -> Type -> Type -> Type@@ -135,7 +129,6 @@ replaceTypeVars' bound name replacement = go bound where go :: [String] -> Type -> Type- go bs (Object r) = Object $ go bs r go _ (TypeVar v) | v == name = replacement go bs (TypeApp t1 t2) = TypeApp (go bs t1) (go bs t2) go bs (SaturatedTypeSynonym name' ts) = SaturatedTypeSynonym name' $ map (go bs) ts@@ -176,7 +169,6 @@ freeTypeVariables = nub . go [] where go :: [String] -> Type -> [String]- go bound (Object r) = go bound r go bound (TypeVar v) | v `notElem` bound = [v] go bound (TypeApp t1 t2) = go bound t1 ++ go bound t2 go bound (SaturatedTypeSynonym _ ts) = concatMap (go bound) ts
− src/Language/PureScript/Values.hs
@@ -1,254 +0,0 @@------------------------------------------------------------------------------------ Module : Language.PureScript.Values--- Copyright : (c) Phil Freeman 2013--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |--- Data types for values, statements, binders and do notation-----------------------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}--module Language.PureScript.Values where--import Language.PureScript.Types-import Language.PureScript.Names--import Data.Data-import Data.Generics (mkQ, everything)---- |--- A guard is just a boolean-valued expression that appears alongside a set of binders----type Guard = Value---- |--- Data type for values----data Value- -- |- -- A numeric literal- --- = NumericLiteral (Either Integer Double)- -- |- -- A string literal- --- | StringLiteral String- -- |- -- A boolean literal- --- | BooleanLiteral Bool- -- |- -- Binary operator application. During the rebracketing phase of desugaring, this data constructor- -- will be removed.- --- | BinaryNoParens (Qualified Ident) Value Value- -- |- -- Explicit parentheses. During the rebracketing phase of desugaring, this data constructor- -- will be removed.- --- | Parens Value- -- |- -- An array literal- --- | ArrayLiteral [Value]- -- |- -- An object literal- --- | ObjectLiteral [(String, Value)]- -- |- -- An record property accessor expression- --- | Accessor String Value- -- |- -- Partial record update- --- | ObjectUpdate Value [(String, Value)]- -- |- -- Function introduction- --- | Abs (Either Ident Binder) Value- -- |- -- Function application- --- | App Value Value- -- |- -- Variable- --- | Var (Qualified Ident)- -- |- -- Conditional (if-then-else expression)- --- | IfThenElse Value Value Value- -- |- -- A data constructor- --- | Constructor (Qualified ProperName)- -- |- -- A case expression. During the case expansion phase of desugaring, top-level binders will get- -- desugared into case expressions, hence the need for guards and multiple binders per branch here.- --- | Case [Value] [CaseAlternative]- -- |- -- A value with a type annotation- --- | TypedValue Bool Value Type- -- |- -- A let binding- --- | Let (Either Binder (Ident, [Either Ident Binder])) Value Value- -- |- -- A do-notation block- --- | Do [DoNotationElement]- -- |- -- A placeholder for a type class dictionary to be inserted later. At the end of type checking, these- -- placeholders will be replaced with actual expressions representing type classes dictionaries which- -- can be evaluated at runtime. The constructor arguments represent (in order): the type class name and- -- instance type, and the type class dictionaries in scope.- --- | TypeClassDictionary (Qualified ProperName, [Type]) [TypeClassDictionaryInScope] deriving (Show, Data, Typeable)---- |--- An alternative in a case statement----data CaseAlternative = CaseAlternative- { -- |- -- A collection of binders with which to match the inputs- --- caseAlternativeBinders :: [Binder]- -- |- -- An optional guard- --- , caseAlternativeGuard :: Maybe Guard- -- |- -- The result expression- --- , caseAlternativeResult :: Value- } deriving (Show, Data, Typeable)---- |--- Data representing a type class dictionary which is in scope----data TypeClassDictionaryInScope- = TypeClassDictionaryInScope {- -- |- -- The identifier with which the dictionary can be accessed at runtime- --- tcdName :: Qualified Ident- -- |- -- The name of the type class to which this type class instance applies- --- , tcdClassName :: Qualified ProperName- -- |- -- The types to which this type class instance applies- --- , tcdInstanceTypes :: [Type]- -- |- -- Type class dependencies which must be satisfied to construct this dictionary- --- , tcdDependencies :: Maybe [(Qualified ProperName, [Type])]- -- |- -- The type of this dictionary- --- , tcdType :: TypeClassDictionaryType- } deriving (Show, Data, Typeable)---- |--- The type of a type class dictionary----data TypeClassDictionaryType- -- |- -- A regular type class dictionary- --- = TCDRegular- -- |- -- A type class dictionary which is an alias for an imported dictionary from another module- --- | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable)---- |--- Find the original dictionary which a type class dictionary in scope refers to----canonicalizeDictionary :: TypeClassDictionaryInScope -> Qualified Ident-canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDRegular, tcdName = nm }) = nm-canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDAlias nm }) = nm---- |--- A statement in a do-notation block----data DoNotationElement- -- |- -- A monadic value without a binder- --- = DoNotationValue Value- -- |- -- A monadic value with a binder- --- | DoNotationBind Binder Value- -- |- -- A let statement, i.e. a pure value with a binder- --- | DoNotationLet Binder Value deriving (Show, Data, Typeable)---- |--- Data type for binders----data Binder- -- |- -- Wildcard binder- --- = NullBinder- -- |- -- A binder which matches a boolean literal- --- | BooleanBinder Bool- -- |- -- A binder which matches a string literal- --- | StringBinder String- -- |- -- A binder which matches a numeric literal- --- | NumberBinder (Either Integer Double)- -- |- -- A binder which binds an identifier- --- | VarBinder Ident- -- |- -- A binder which matches a data constructor- --- | ConstructorBinder (Qualified ProperName) [Binder]- -- |- -- A binder which matches a record and binds its properties- --- | ObjectBinder [(String, Binder)]- -- |- -- A binder which matches an array and binds its elements- --- | ArrayBinder [Binder]- -- |- -- A binder which matches an array and binds its head and tail- --- | ConsBinder Binder Binder- -- |- -- A binder which binds its input to an identifier- --- | NamedBinder Ident Binder deriving (Show, Data, Typeable)----- |--- Collect all names introduced in binders in an expression----binderNames :: (Data d) => d -> [Ident]-binderNames = everything (++) (mkQ [] go)- where- go (VarBinder ident) = [ident]- go (NamedBinder ident _) = [ident]- go _ = []