purescript 0.6.8 → 0.6.9
raw patch · 52 files changed
+2102/−1058 lines, 52 filesdep +boxesdep ~base
Dependencies added: boxes
Dependency ranges changed: base
Files
- LICENSE +62/−0
- examples/passing/InstanceBeforeClass.purs +9/−0
- examples/passing/OperatorAssociativity.purs +16/−0
- examples/passing/SequenceDesugared.purs +34/−0
- hierarchy/Main.hs +1/−1
- prelude/prelude.purs +389/−15
- psc-docs/Main.hs +37/−6
- psc-make/Main.hs +1/−1
- psc/Main.hs +1/−1
- psci/Commands.hs +12/−21
- psci/Main.hs +119/−66
- psci/Parser.hs +87/−44
- purescript.cabal +5/−3
- src/Control/Monad/Supply.hs +43/−0
- src/Control/Monad/Supply/Class.hs +36/−0
- src/Control/Monad/Unify.hs +10/−6
- src/Language/PureScript.hs +40/−22
- src/Language/PureScript/AST/Declarations.hs +21/−13
- src/Language/PureScript/AST/SourcePos.hs +2/−2
- src/Language/PureScript/CodeGen/Externs.hs +2/−2
- src/Language/PureScript/CodeGen/JS.hs +288/−292
- src/Language/PureScript/CoreFn/Desugar.hs +9/−4
- src/Language/PureScript/CoreFn/Module.hs +3/−1
- src/Language/PureScript/DeadCodeElimination.hs +2/−2
- src/Language/PureScript/Errors.hs +459/−88
- src/Language/PureScript/ModuleDependencies.hs +1/−1
- src/Language/PureScript/Parser/Declarations.hs +15/−7
- src/Language/PureScript/Pretty/JS.hs +14/−14
- src/Language/PureScript/Pretty/Values.hs +3/−3
- src/Language/PureScript/Renamer.hs +1/−1
- src/Language/PureScript/Sugar.hs +10/−7
- src/Language/PureScript/Sugar/BindingGroups.hs +19/−16
- src/Language/PureScript/Sugar/CaseDeclarations.hs +40/−16
- src/Language/PureScript/Sugar/DoNotation.hs +12/−9
- src/Language/PureScript/Sugar/Names.hs +94/−101
- src/Language/PureScript/Sugar/ObjectWildcards.hs +11/−7
- src/Language/PureScript/Sugar/Operators.hs +21/−19
- src/Language/PureScript/Sugar/TypeClasses.hs +25/−18
- src/Language/PureScript/Sugar/TypeDeclarations.hs +11/−8
- src/Language/PureScript/Supply.hs +0/−56
- src/Language/PureScript/TypeChecker.hs +44/−52
- src/Language/PureScript/TypeChecker/Entailment.hs +2/−45
- src/Language/PureScript/TypeChecker/Kinds.hs +5/−6
- src/Language/PureScript/TypeChecker/Monad.hs +13/−13
- src/Language/PureScript/TypeChecker/Rows.hs +1/−1
- src/Language/PureScript/TypeChecker/Skolems.hs +2/−3
- src/Language/PureScript/TypeChecker/Subsumption.hs +2/−9
- src/Language/PureScript/TypeChecker/Synonyms.hs +12/−12
- src/Language/PureScript/TypeChecker/Types.hs +25/−35
- src/Language/PureScript/TypeChecker/Unify.hs +7/−8
- src/Language/PureScript/TypeClassDictionaries.hs +23/−0
- tests/Main.hs +1/−1
LICENSE view
@@ -37,6 +37,8 @@ transformers unordered-containers utf8-string+ split+ boxes base LICENSE file: @@ -620,3 +622,63 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++split LICENSE file:++ Copyright (c) 2008 Brent Yorgey, Louis Wasserman++ All rights reserved.++ Redistribution and use in source and binary forms, with or without+ modification, are permitted provided that the following conditions+ are met:+ 1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ 2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ 3. Neither the name of the author nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ SUCH DAMAGE.++boxes LICENSE file:++ Copyright (c) Brent Yorgey 2008++ Redistribution and use in source and binary forms, with or without+ modification, are permitted provided that the following conditions+ are met:+ 1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ 2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ 3. Neither the name of the author nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++ All other rights are reserved.++ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ SUCH DAMAGE.
+ examples/passing/InstanceBeforeClass.purs view
@@ -0,0 +1,9 @@+module Main where++instance fooNumber :: Foo Number where+ foo = 0++class Foo a where+ foo :: a++main = Debug.Trace.trace "Done"
examples/passing/OperatorAssociativity.purs view
@@ -40,3 +40,19 @@ assert (4 % (9 / 3) == 1) "4 % (9 / 3) == 1" assert ((4 % 9) / 2 == 2) "(4 % 9) / 2 == 2"++ assert (not (1 < 0) == true) "not (1 < 0) == true"+ assert (not (complement (1 + 10) == 8) == true) "not (complement (1 + 10) == 8) == true"+ assert (not ((negate 1) < 0) == false) "not ((negate 1) < 0) == false"++ assert (negate (1 + 10) == -11) "negate (1 + 10) == -11"++ assert (2 * 3 / 4 == 1.5) "2 * 3 / 4 == 1.5"+ assert (1 * 2 * 3 * 4 * 5 / 6 == 20) "1 * 2 * 3 * 4 * 5 / 6 == 20"+ assert (complement (2 / 3 * 4) == -3) "complement (2 / 3 * 4) == -3"++ assert (1 + 10 - 5 == 6) "1 + 10 - 5 == 6"+ assert (1 + 10 * 5 == 51) "1 + 10 * 5 == 51"+ assert (10 * 5 - 1 == 49) "10 * 5 - 1 == 49"++ trace "Success!"
+ examples/passing/SequenceDesugared.purs view
@@ -0,0 +1,34 @@+module Main where++import Control.Monad.Eff++data Sequence t = Sequence (forall m a. (Monad m) => t (m a) -> m (t a))++sequence :: forall t. Sequence t -> (forall m a. (Monad m) => t (m a) -> m (t a))+sequence (Sequence s) = s++sequenceArraySeq :: forall m a. (Monad m) => Array (m a) -> m (Array a)+sequenceArraySeq [] = pure []+sequenceArraySeq (x:xs) = (:) <$> x <*> sequenceArraySeq xs++sequenceArray :: Sequence []+sequenceArray = Sequence (sequenceArraySeq)++sequenceArray' :: Sequence []+sequenceArray' = Sequence ((\val -> case val of+ [] -> pure []+ (x:xs) -> (:) <$> x <*> sequence sequenceArray' xs))++sequenceArray'' :: Sequence []+sequenceArray'' = Sequence (sequenceArraySeq :: forall m a. (Monad m) => Array (m a) -> m (Array a))++sequenceArray''' :: Sequence []+sequenceArray''' = Sequence ((\val -> case val of+ [] -> pure []+ (x:xs) -> (:) <$> x <*> sequence sequenceArray''' xs) :: forall m a. (Monad m) => Array (m a) -> m (Array a))++main = do+ sequence sequenceArray $ [Debug.Trace.trace "Done"]+ sequence sequenceArray' $ [Debug.Trace.trace "Done"]+ sequence sequenceArray'' $ [Debug.Trace.trace "Done"]+ sequence sequenceArray''' $ [Debug.Trace.trace "Done"]
hierarchy/Main.hs view
@@ -64,7 +64,7 @@ case modules of Left err -> hPutStr stderr (show err) >> exitFailure Right ms -> do- for_ ms $ \(P.Module moduleName decls _) ->+ for_ ms $ \(P.Module _ moduleName decls _) -> let name = runModuleName moduleName tcs = filter P.isTypeClassDeclaration decls supers = sort . nub . filter (not . null) $ fmap superClasses tcs
prelude/prelude.purs view
@@ -20,7 +20,7 @@ , negate , DivisionRing , Num- , Eq, (==), (/=), refEq, refIneq+ , Eq, (==), (/=) , Ord, Ordering(..), compare, (<), (>), (<=), (>=) , Bits, (.&.), (.|.), (.^.), shl, shr, zshr, complement , BoolLike, (&&), (||)@@ -31,27 +31,38 @@ -- | An alias for `true`, which can be useful in guard clauses: -- |- -- | E.g.+ -- | ```purescript+ -- | max x y | x >= y = x+ -- | | otherwise = y+ -- | ``` -- |- -- | max x y | x >= y = x- -- | | otherwise = y otherwise :: Boolean otherwise = true -- | Flips the order of the arguments to a function of two arguments.+ -- |+ -- | ```purescript+ -- | flip const 1 2 = const 2 1 = 2+ -- | ```+ -- | flip :: forall a b c. (a -> b -> c) -> b -> a -> c flip f b a = f a b -- | Returns its first argument and ignores its second.+ -- |+ -- | ```purescript+ -- | const 1 "hello" = 1+ -- | ```+ -- | const :: forall a b. a -> b -> a const a _ = a -- | This function returns its first argument, and can be used to assert type equalities. -- | This can be useful when types are otherwise ambiguous. -- |- -- | E.g.- -- |- -- | main = print $ [] `asTypeOf` [0]+ -- | ```purescript+ -- | main = print $ [] `asTypeOf` [0]+ -- | ``` -- | -- | If instead, we had written `main = print []`, the type of the argument `[]` would have -- | been ambiguous, resulting in a compile-time error.@@ -61,15 +72,33 @@ infixr 9 >>> infixr 9 <<< + -- | A `Semigroupoid` is similar to a [`Category`](#category) but does not require an identity+ -- | element `id`, just composable morphisms.+ -- |+ -- | `Semigroupoid`s should obey the following rule:+ -- |+ -- | - Associativity: `p <<< (q <<< r) = (p <<< q) <<< r`+ -- |+ -- | One example of a `Semigroupoid` is the function type constructor `(->)`, with `(<<<)` defined+ -- | as function composition. class Semigroupoid a where (<<<) :: forall b c d. a c d -> a b c -> a b d instance semigroupoidArr :: Semigroupoid (->) where (<<<) f g x = f (g x) + -- | Forwards composition, or `(<<<)` with its arguments reversed. (>>>) :: forall a b c d. (Semigroupoid a) => a b c -> a c d -> a b d (>>>) f g = g <<< f + -- | `Category`s consist of objects and composable morphisms between them, and as such are+ -- | [`Semigroupoids`](#semigroupoid), but unlike `semigroupoids` must have an identity element.+ -- |+ -- | `Category`s should obey the following rules.+ -- |+ -- | - Left Identity: `id <<< p = p`+ -- | - Right Identity: `p <<< id = p`+ -- | class (Semigroupoid a) <= Category a where id :: forall t. a t t @@ -79,17 +108,57 @@ infixr 0 $ infixl 0 # + -- | Applies a function to its argument+ -- |+ -- | ```purescript+ -- | length $ groupBy productCategory $ filter isInStock products+ -- | ```+ -- |+ -- | is equivalent to+ -- |+ -- | ```purescript+ -- | length (groupBy productCategory (filter isInStock (products)))+ -- | ```+ -- |+ -- | `($)` is different from [`(#)`](#-2) because it is right-infix instead of left, so+ -- | `a $ b $ c $ d x` = `a $ (b $ (c $ (d $ x)))` = `a (b (c (d x)))`+ -- | ($) :: forall a b. (a -> b) -> a -> b ($) f x = f x + -- | Applies a function to its argument+ -- |+ -- | ```purescript+ -- | products # groupBy productCategory # filter isInStock # length+ -- | ```+ -- |+ -- | is equivalent to+ -- |+ -- | ```purescript+ -- | length (groupBy productCategory (filter isInStock (products)))+ -- | ```+ -- |+ -- | `(#)` is different from [`($)`](#-1) because it is left-infix instead of right, so+ -- | `x # a # b # c # d` = `(((x # a) # b) # c) # d` = `d (c (b (a x)))`+ -- | (#) :: forall a b. a -> (a -> b) -> b (#) x f = f x infixr 6 : + -- | An infix alias for `cons`.+ -- |+ -- | Note, the running time of this function is `O(n)`. (:) :: forall a. a -> [a] -> [a] (:) = cons + -- | Attaches an element to the front of an array, creating a new array.+ -- |+ -- | ```purescript+ -- | cons 1 [2, 3, 4] = [1, 2, 3, 4]+ -- | ```+ -- |+ -- | Note, the running time of this function is `O(n)`. foreign import cons """ function cons(e) {@@ -99,6 +168,10 @@ } """ :: forall a. a -> [a] -> [a] + -- | The `Show` type class represents those types which can be converted into a human-readable `String` representation.+ -- |+ -- | While not required, it is recommended that for any expression `x`, the string `show x` be executable PureScript code+ -- | which evaluates to the same value as the expression `x`. class Show a where show :: a -> String @@ -148,41 +221,166 @@ infixl 4 <$> infixl 1 <#> + -- | A `Functor` is a type constructor which supports a mapping operation `(<$>)`.+ -- |+ -- | `(<$>)` can be used to turn functions `a -> b` into functions `f a -> f b` whose argument and return+ -- | types use the type constructor `f` to represent some computational context.+ -- |+ -- | `Functor` instances should satisfy the following laws:+ -- |+ -- | - Identity: `(<$>) id = id`+ -- | - Composition: `(<$>) (f <<< g) = (f <$>) <<< (g <$>)`+ -- | class Functor f where (<$>) :: forall a b. (a -> b) -> f a -> f b + -- | `(<#>)` is `(<$>)` with its arguments reversed. For example:+ -- |+ -- | ```purescript+ -- | [1, 2, 3] <#> \n -> n * n+ -- | ``` (<#>) :: forall f a b. (Functor f) => f a -> (a -> b) -> f b (<#>) fa f = f <$> fa + -- | The `void` function is used to ignore the type wrapped by a [`Functor`](#functor), replacing it with `Unit` and+ -- | keeping only the type information provided by the type constructor itself.+ -- |+ -- | `void` is often useful when using `do` notation to change the return type of a monadic computation:+ -- |+ -- | ```purescript+ -- | main = forE 1 10 \n -> void do+ -- | print n+ -- | print (n * n)+ -- | ``` void :: forall f a. (Functor f) => f a -> f Unit void fa = const unit <$> fa infixl 4 <*> + -- | The `Apply` class provides the `(<*>)` which is used to apply a function to an argument under a type constructor.+ -- |+ -- | `Apply` can be used to lift functions of two or more arguments to work on values wrapped with the type constructor `f`.+ -- | It might also be understood in terms of the `lift2` function:+ -- |+ -- | ```purescript+ -- | lift2 :: forall f a b c. (Apply f) => (a -> b -> c) -> f a -> f b -> f c+ -- | lift2 f a b = f <$> a <*> b+ -- | ```+ -- |+ -- | `(<*>)` is recovered from `lift2` as `lift2 ($)`. That is, `(<*>)` lifts the function application operator `($)` to arguments+ -- | wrapped with the type constructor `f`.+ -- |+ -- | `Apply` instances should satisfy the following law:+ -- |+ -- | - Associative Composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)`+ -- |+ -- | Formally, `Apply` represents a strong lax semi-monoidal endofunctor. class (Functor f) <= Apply f where (<*>) :: forall a b. f (a -> b) -> f a -> f b + -- | The `Applicative` type class extends the [`Apply`](#apply) type class with a `pure` function, which can be used to+ -- | create values of type `f a` from values of type `a`.+ -- |+ -- | Where [`Apply`](#apply) provides the ability to lift functions of two or more arguments to functions whose arguments are wrapped using `f`,+ -- | and [`Functor`](#functor) provides the ability to lift functions of one argument, `pure` can be seen as the function which lifts functions of+ -- | _zero_ arguments. That is, `Applicative` functors support a lifting operation for any number of function arguments.+ -- |+ -- | `Applicative` instances should satisfy the following laws:+ -- |+ -- | - Identity: `(pure id) <*> v = v`+ -- | - Composition: `(pure <<<) <*> f <*> g <*> h = f <*> (g <*> h)`+ -- | - Homomorphism: `(pure f) <*> (pure x) = pure (f x)`+ -- | - Interchange: `u <*> (pure y) = (pure ($ y)) <*> u`+ -- | class (Apply f) <= Applicative f where pure :: forall a. a -> f a + -- | `liftA1` provides a default implementation of `(<$>)` for any [`Applicative`](#applicative) functor,+ -- | without using `(<$>)` as provided by the [`Functor`](#functor)-[`Applicative`](#applicative) superclass relationship.+ -- |+ -- | `liftA1` can therefore be used to write [`Functor`](#functor) instances as follows:+ -- |+ -- | ```purescript+ -- | instance functorF :: Functor F where+ -- | (<$>) = liftA1+ -- | ``` liftA1 :: forall f a b. (Applicative f) => (a -> b) -> f a -> f b liftA1 f a = pure f <*> a infixl 1 >>= + -- | The `Bind` type class extends the [`Apply`](#apply) type class with a "bind" operation `(>>=)` which composes computations+ -- | in sequence, using the return value of one computation to determine the next computation.+ -- |+ -- | The `>>=` operator can also be expressed using `do` notation, as follows:+ -- |+ -- | ```purescript+ -- | x >>= f = do y <- x+ -- | f y+ -- | ```+ -- |+ -- | where the function argument of `f` is given the name `y`.+ -- |+ -- | `Bind` instances should satisfy the following law:+ -- |+ -- | - Associativity: `(x >>= f) >>= g = x >>= (\k => f k >>= g)`+ -- |+ -- | Or, expressed using `do` notation:+ -- |+ -- | - Associativity: `do { z <- do { y <- x ; f y } ; g z } = do { k <- x ; do { y <- f k ; g y } }`+ -- |+ -- | Associativity tells us that we can regroup operations which use do-notation, so that we can unambiguously write, for example:+ -- |+ -- | ```purescript+ -- | do x <- m1+ -- | y <- m2 x+ -- | m3 x y+ -- | ``` class (Apply m) <= Bind m where (>>=) :: forall a b. m a -> (a -> m b) -> m b + -- | The `Monad` type class combines the operations of the `Bind` and `Applicative` type classes. Therefore, `Monad` instances+ -- | represent type constructors which support sequential composition, and also lifting of functions of arbitrary arity.+ -- |+ -- | `Monad` instances should satisfy the following laws:+ -- |+ -- | - Left Identity: `pure x >>= f = f x`+ -- | - Right Identity: `x >>= pure = x`+ -- |+ -- | Or, expressed using `do` notation:+ -- |+ -- | - Left Identity: `do { y <- pure x ; f y } = f x`+ -- | - Right Identity: `do { y <- x ; pure y } = x`+ -- | class (Applicative m, Bind m) <= Monad m + -- | `return` is an alias for `pure`. return :: forall m a. (Monad m) => a -> m a return = pure + -- | `liftM1` provides a default implementation of `(<$>)` for any [`Monad`](#monad),+ -- | without using `(<$>)` as provided by the [`Functor`](#functor)-[`Monad`](#monad) superclass relationship.+ -- |+ -- | `liftM1` can therefore be used to write [`Functor`](#functor) instances as follows:+ -- |+ -- | ```purescript+ -- | instance functorF :: Functor F where+ -- | (<$>) = liftM1+ -- | ``` liftM1 :: forall m a b. (Monad m) => (a -> b) -> m a -> m b liftM1 f a = do a' <- a return (f a') + -- | `ap` provides a default implementation of `(<*>)` for any [`Monad`](#monad),+ -- | without using `(<*>)` as provided by the [`Apply`](#apply)-[`Monad`](#monad) superclass relationship.+ -- |+ -- | `ap` can therefore be used to write [`Apply`](#apply) instances as follows:+ -- |+ -- | ```purescript+ -- | instance applyF :: Apply F where+ -- | (<*>) = ap+ -- | ``` ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b ap f a = do f' <- f@@ -210,28 +408,43 @@ infixl 6 - infixl 6 + - -- | Addition and multiplication+ -- | Addition and multiplication, satisfying the following laws:+ -- |+ -- | - `a` is a commutative monoid under addition+ -- | - `a` is a monoid under multiplication+ -- | - multiplication distributes over addition+ -- | - multiplication by `zero` annihilates `a`+ -- | class Semiring a where (+) :: a -> a -> a zero :: a (*) :: a -> a -> a one :: a - -- | Semiring with modulo operation and division where- -- | ```a / b * b + (a `mod` b) = a```+ -- | Addition, multiplication, modulo operation and division, satisfying:+ -- |+ -- | - ```a / b * b + (a `mod` b) = a```+ -- | class (Semiring a) <= ModuloSemiring a where (/) :: a -> a -> a mod :: a -> a -> a - -- | Addition, multiplication, and subtraction+ -- | Addition, multiplication, and subtraction.+ -- |+ -- | Has the same laws as `Semiring` but additionally satisfying:+ -- |+ -- | - `a` is an abelian group under addition+ -- | class (Semiring a) <= Ring a where (-) :: a -> a -> a negate :: forall a. (Ring a) => a -> a negate a = zero - a - -- | Ring where every nonzero element has a multiplicative inverse (possibly- -- | a non-commutative field) so that ```a `mod` b = zero```+ -- | Ring where every nonzero element has a multiplicative inverse so that:+ -- |+ -- | - ```a `mod` b = zero```+ -- | class (Ring a, ModuloSemiring a) <= DivisionRing a -- | A commutative field@@ -301,14 +514,29 @@ instance numNumber :: Num Number + -- | The `Unit` type has a single inhabitant, called `unit`. It represents values with no computational content.+ -- |+ -- | `Unit` is often used, wrapped in a monadic type constructor, as the return type of a computation where only+ -- | the _effects_ are important. newtype Unit = Unit {} + -- | `unit` is the sole inhabitant of the `Unit` type. unit :: Unit unit = Unit {} infix 4 == infix 4 /= + -- | The `Eq` type class represents types which support decidable equality.+ -- |+ -- | `Eq` instances should satisfy the following laws:+ -- |+ -- | - Reflexivity: `x == x = true`+ -- | - Symmetry: `x == y = y == x`+ -- | - Transitivity: if `x == y` and `y == z` then `x == z`+ -- | - Negation: `x /= y = not (x == y)`+ -- |+ -- | `(/=)` may be implemented in terms of `(==)`, but it might give a performance improvement to implement it separately. class Eq a where (==) :: a -> a -> Boolean (/=) :: a -> a -> Boolean@@ -366,6 +594,11 @@ (==) xs ys = eqArrayImpl (==) xs ys (/=) xs ys = not (xs == ys) + -- | The `Ordering` data type represents the three possible outcomes of comparing two values:+ -- |+ -- | `LT` - The first value is _less than_ the second.+ -- | `GT` - The first value is _greater than_ the second.+ -- | `EQ` - The first value is _equal to_ or _incomparable to_ the second. data Ordering = LT | GT | EQ instance eqOrdering :: Eq Ordering where@@ -380,11 +613,25 @@ show GT = "GT" show EQ = "EQ" + instance semigroupOrdering :: Semigroup Ordering where+ (<>) LT _ = LT+ (<>) GT _ = GT+ (<>) EQ y = y++ -- | The `Ord` type class represents types which support comparisons.+ -- |+ -- | `Ord` instances should satisfy the laws of _partially orderings_:+ -- |+ -- | - Reflexivity: `a <= a`+ -- | - Antisymmetry: if `a <= b` and `b <= a` then `a = b`+ -- | - Transitivity: if `a <= b` and `b <= c` then `a <= c`+ -- | class (Eq a) <= Ord a where compare :: a -> a -> Ordering infixl 4 < + -- | Test whether one value is _strictly less than_ another. (<) :: forall a. (Ord a) => a -> a -> Boolean (<) a1 a2 = case a1 `compare` a2 of LT -> true@@ -392,6 +639,7 @@ infixl 4 > + -- | Test whether one value is _strictly greater than_ another. (>) :: forall a. (Ord a) => a -> a -> Boolean (>) a1 a2 = case a1 `compare` a2 of GT -> true@@ -399,6 +647,7 @@ infixl 4 <= + -- | Test whether one value is _non-strictly less than_ another. (<=) :: forall a. (Ord a) => a -> a -> Boolean (<=) a1 a2 = case a1 `compare` a2 of GT -> false@@ -406,6 +655,7 @@ infixl 4 >= + -- | Test whether one value is _non-strictly greater than_ another. (>=) :: forall a. (Ord a) => a -> a -> Boolean (>=) a1 a2 = case a1 `compare` a2 of LT -> false@@ -456,6 +706,7 @@ infixl 10 .|. infixl 10 .^. + -- | The `Bits` type class identifies types which support bitwise operations. class Bits b where (.&.) :: b -> b -> b (.|.) :: b -> b -> b@@ -538,6 +789,10 @@ infixr 2 || infixr 3 && + -- | The `BoolLike` type class identifies types which support Boolean operations.+ -- |+ -- | `BoolLike` instances are required to satisfy the laws of a _Boolean algebra_.+ -- | class BoolLike b where (&&) :: b -> b -> b (||) :: b -> b -> b@@ -575,6 +830,13 @@ infixr 5 <> + -- | The `Semigroup` type class identifies an associative operation on a type.+ -- |+ -- | `Semigroup` instances are required to satisfy the following law:+ -- |+ -- | - Associativity: `(x <> y) <> z = x <> (y <> z)`+ -- |+ -- | For example, the `String` type is an instance of `Semigroup`, where `(<>)` is defined to be string concatenation. class Semigroup a where (<>) :: a -> a -> a @@ -598,26 +860,57 @@ infixr 5 ++ + -- | `(++)` is an alias for `(<>)`. (++) :: forall s. (Semigroup s) => s -> s -> s (++) = (<>) module Data.Function where + -- | The `on` function is used to change the domain of a binary operator.+ -- |+ -- | For example, we can create a function which compares two records based on the values of their `x` properties:+ -- |+ -- | ```purescript+ -- | compareX :: forall r. { x :: Number | r } -> { x :: Number | r } -> Ordering+ -- | compareX = compare `on` _.x+ -- | ``` on :: forall a b c. (b -> b -> c) -> (a -> b) -> a -> a -> c on f g x y = g x `f` g y + -- | A function of zero arguments foreign import data Fn0 :: * -> *++ -- | A function of one argument foreign import data Fn1 :: * -> * -> *++ -- | A function of two arguments foreign import data Fn2 :: * -> * -> * -> *++ -- | A function of three arguments foreign import data Fn3 :: * -> * -> * -> * -> *++ -- | A function of four arguments foreign import data Fn4 :: * -> * -> * -> * -> * -> *++ -- | A function of five arguments foreign import data Fn5 :: * -> * -> * -> * -> * -> * -> *++ -- | A function of six arguments foreign import data Fn6 :: * -> * -> * -> * -> * -> * -> * -> *++ -- | A function of seven arguments foreign import data Fn7 :: * -> * -> * -> * -> * -> * -> * -> * -> *++ -- | A function of eight arguments foreign import data Fn8 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> *++ -- | A function of nine arguments foreign import data Fn9 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *++ -- | A function of ten arguments foreign import data Fn10 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * + -- | Create a function of no arguments foreign import mkFn0 """ function mkFn0(fn) {@@ -627,6 +920,7 @@ } """ :: forall a. (Unit -> a) -> Fn0 a + -- | Create a function of one argument foreign import mkFn1 """ function mkFn1(fn) {@@ -636,6 +930,7 @@ } """ :: forall a b. (a -> b) -> Fn1 a b + -- | Create a function of two arguments from a curried function foreign import mkFn2 """ function mkFn2(fn) {@@ -645,6 +940,7 @@ } """ :: forall a b c. (a -> b -> c) -> Fn2 a b c + -- | Create a function of three arguments from a curried function foreign import mkFn3 """ function mkFn3(fn) {@@ -654,6 +950,7 @@ } """ :: forall a b c d. (a -> b -> c -> d) -> Fn3 a b c d + -- | Create a function of four arguments from a curried function foreign import mkFn4 """ function mkFn4(fn) {@@ -663,6 +960,7 @@ } """ :: forall a b c d e. (a -> b -> c -> d -> e) -> Fn4 a b c d e + -- | Create a function of five arguments from a curried function foreign import mkFn5 """ function mkFn5(fn) {@@ -672,6 +970,7 @@ } """ :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Fn5 a b c d e f + -- | Create a function of six arguments from a curried function foreign import mkFn6 """ function mkFn6(fn) {@@ -681,6 +980,7 @@ } """ :: forall a b c d e f g. (a -> b -> c -> d -> e -> f -> g) -> Fn6 a b c d e f g + -- | Create a function of seven arguments from a curried function foreign import mkFn7 """ function mkFn7(fn) {@@ -690,6 +990,7 @@ } """ :: forall a b c d e f g h. (a -> b -> c -> d -> e -> f -> g -> h) -> Fn7 a b c d e f g h + -- | Create a function of eight arguments from a curried function foreign import mkFn8 """ function mkFn8(fn) {@@ -699,6 +1000,7 @@ } """ :: forall a b c d e f g h i. (a -> b -> c -> d -> e -> f -> g -> h -> i) -> Fn8 a b c d e f g h i + -- | Create a function of nine arguments from a curried function foreign import mkFn9 """ function mkFn9(fn) {@@ -708,6 +1010,7 @@ } """ :: forall a b c d e f g h i j. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j) -> Fn9 a b c d e f g h i j + -- | Create a function of ten arguments from a curried function foreign import mkFn10 """ function mkFn10(fn) {@@ -717,6 +1020,7 @@ } """ :: forall a b c d e f g h i j k. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k) -> Fn10 a b c d e f g h i j k + -- | Apply a function of no arguments foreign import runFn0 """ function runFn0(fn) {@@ -724,6 +1028,7 @@ } """ :: forall a. Fn0 a -> a + -- | Apply a function of one argument foreign import runFn1 """ function runFn1(fn) {@@ -733,6 +1038,7 @@ } """ :: forall a b. Fn1 a b -> a -> b + -- | Apply a function of two arguments foreign import runFn2 """ function runFn2(fn) {@@ -744,6 +1050,7 @@ } """ :: forall a b c. Fn2 a b c -> a -> b -> c + -- | Apply a function of three arguments foreign import runFn3 """ function runFn3(fn) {@@ -757,6 +1064,7 @@ } """ :: forall a b c d. Fn3 a b c d -> a -> b -> c -> d + -- | Apply a function of four arguments foreign import runFn4 """ function runFn4(fn) {@@ -772,6 +1080,7 @@ } """ :: forall a b c d e. Fn4 a b c d e -> a -> b -> c -> d -> e + -- | Apply a function of five arguments foreign import runFn5 """ function runFn5(fn) {@@ -789,6 +1098,7 @@ } """ :: forall a b c d e f. Fn5 a b c d e f -> a -> b -> c -> d -> e -> f + -- | Apply a function of six arguments foreign import runFn6 """ function runFn6(fn) {@@ -808,6 +1118,7 @@ } """ :: forall a b c d e f g. Fn6 a b c d e f g -> a -> b -> c -> d -> e -> f -> g + -- | Apply a function of seven arguments foreign import runFn7 """ function runFn7(fn) {@@ -829,6 +1140,7 @@ } """ :: forall a b c d e f g h. Fn7 a b c d e f g h -> a -> b -> c -> d -> e -> f -> g -> h + -- | Apply a function of eight arguments foreign import runFn8 """ function runFn8(fn) {@@ -852,6 +1164,7 @@ } """ :: forall a b c d e f g h i. Fn8 a b c d e f g h i -> a -> b -> c -> d -> e -> f -> g -> h -> i + -- | Apply a function of nine arguments foreign import runFn9 """ function runFn9(fn) {@@ -877,6 +1190,7 @@ } """ :: forall a b c d e f g h i j. Fn9 a b c d e f g h i j -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j + -- | Apply a function of ten arguments foreign import runFn10 """ function runFn10(fn) {@@ -906,6 +1220,9 @@ module Prelude.Unsafe where + -- | Find the element of an array at the specified index.+ -- |+ -- | Note: this function can cause unpredictable failure at runtime if the index is out-of-bounds. foreign import unsafeIndex """ function unsafeIndex(xs) {@@ -915,8 +1232,18 @@ } """ :: forall a. [a] -> Number -> a -module Control.Monad.Eff where+module Control.Monad.Eff+ ( Eff()+ , Pure()+ , runPure+ , untilE, whileE, forE, foreachE+ ) where + -- | The `Eff` type constructor is used to represent _native_ effects.+ -- |+ -- | See [Handling Native Effects with the Eff Monad](https://github.com/purescript/purescript/wiki/Handling-Native-Effects-with-the-Eff-Monad) for more details.+ -- |+ -- | The first type parameter is a row of effects which represents the contexts in which a computation can be run, and the second type parameter is the return type. foreign import data Eff :: # ! -> * -> * foreign import returnE@@ -939,8 +1266,15 @@ } """ :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b + -- | The `Pure` type synonym represents _pure_ computations, i.e. ones in which all effects have been handled.+ -- |+ -- | The `runPure` function can be used to run pure computations and obtain their result. type Pure a = forall e. Eff e a + -- | Run a pure computation and return its result.+ -- |+ -- | Note: since this function has a rank-2 type, it may cause problems to apply this function using the `$` operator. The recommended approach+ -- | is to use parentheses instead. foreign import runPure """ function runPure(f) {@@ -962,6 +1296,10 @@ instance monadEff :: Monad (Eff e) + -- | Loop until a condition becomes `true`.+ -- |+ -- | `untilE b` is an effectful computation which repeatedly runs the effectful computation `b`,+ -- | until its return value is `true`. foreign import untilE """ function untilE(f) {@@ -972,6 +1310,10 @@ } """ :: forall e. Eff e Boolean -> Eff e Unit + -- | Loop while a condition is `true`.+ -- |+ -- | `whileE b m` is effectful computation which runs the effectful computation `b`. If its result is+ -- | `true`, it runs the effectful computation `m` and loops. If not, the computation ends. foreign import whileE """ function whileE(f) {@@ -986,6 +1328,10 @@ } """ :: forall e a. Eff e Boolean -> Eff e a -> Eff e Unit + -- | Loop over a consecutive collection of numbers.+ -- |+ -- | `forE lo hi f` runs the computation returned by the function `f` for each of the inputs+ -- | between `lo` (inclusive) and `hi` (exclusive). foreign import forE """ function forE(lo) {@@ -1001,7 +1347,9 @@ } """ :: forall e. Number -> Number -> (Number -> Eff e Unit) -> Eff e Unit -+ -- | Loop over an array of values.+ -- |+ -- | `foreach xs f` runs the computation returned by the function `f` for each of the inputs `xs`. foreign import foreachE """ function foreachE(as) {@@ -1019,6 +1367,9 @@ import Control.Monad.Eff + -- | Change the type of an effectful computation, allowing it to be run in another context.+ -- |+ -- | Note: use of this function can result in arbitrary side-effects. foreign import unsafeInterleaveEff """ function unsafeInterleaveEff(f) {@@ -1030,8 +1381,10 @@ import Control.Monad.Eff + -- | The `Trace` effect represents those computations which write to the console. foreign import data Trace :: ! + -- | Write a `String` to the console. foreign import trace """ function trace(s) {@@ -1042,6 +1395,7 @@ } """ :: forall r. String -> Eff (trace :: Trace | r) Unit + -- | Write a value to the console, using its `Show` instance to produce a `String`. print :: forall a r. (Show a) => a -> Eff (trace :: Trace | r) Unit print o = trace (show o) @@ -1049,10 +1403,17 @@ import Control.Monad.Eff + -- | The `ST` effect represents _local mutation_, i.e. mutation which does not "escape" into the surrounding computation.+ -- |+ -- | An `ST` computation is parameterized by a phantom type which is used to restrict the set of reference cells it is allowed to access.+ -- |+ -- | The `runST` function can be used to handle the `ST` effect. foreign import data ST :: * -> ! + -- | The type `STRef s a` represents a mutable reference holding a value of type `a`, which can be used with the `ST s` effect. foreign import data STRef :: * -> * -> * + -- | Create a new mutable reference. foreign import newSTRef """ function newSTRef(val) {@@ -1062,6 +1423,7 @@ } """ :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a) + -- | Read the current value of a mutable reference. foreign import readSTRef """ function readSTRef(ref) {@@ -1071,6 +1433,7 @@ } """ :: forall a h r. STRef h a -> Eff (st :: ST h | r) a + -- | Modify the value of a mutable reference by applying a function to the current value. foreign import modifySTRef """ function modifySTRef(ref) {@@ -1082,6 +1445,7 @@ } """ :: forall a h r. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a + -- | Set the value of a mutable reference. foreign import writeSTRef """ function writeSTRef(ref) {@@ -1093,6 +1457,12 @@ } """ :: forall a h r. STRef h a -> a -> Eff (st :: ST h | r) a + -- | Run an `ST` computation.+ -- |+ -- | Note: the type of `runST` uses a rank-2 type to constrain the phantom type `s`, such that the computation must not leak any mutable references+ -- | to the surrounding computation.+ -- |+ -- | It may cause problems to apply this function using the `$` operator. The recommended approach is to use parentheses instead. foreign import runST """ function runST(f) {@@ -1100,5 +1470,9 @@ } """ :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a + -- | A convenience function which combines `runST` with `runPure`, which can be used when the only required effect is `ST`.+ -- |+ -- | Note: since this function has a rank-2 type, it may cause problems to apply this function using the `$` operator. The recommended approach+ -- | is to use parentheses instead. pureST :: forall a. (forall h r. Eff (st :: ST h | r) a) -> a pureST st = runPure (runST st)
psc-docs/Main.hs view
@@ -30,21 +30,37 @@ import System.Exit (exitSuccess, exitFailure) import System.IO (hPutStrLn, stderr) +import Etags+import Ctags++-- Available output formats+data Format = Markdown -- Output documentation in Markdown format+ | Ctags -- Output ctags symbol index suitable for use with vi+ | Etags -- Output etags symbol index suitable for use with emacs+ data PSCDocsOptions = PSCDocsOptions- { pscdInputFiles :: [FilePath]+ { pscdFormat :: Format+ , pscdInputFiles :: [FilePath] } docgen :: PSCDocsOptions -> IO ()-docgen (PSCDocsOptions input) = do+docgen (PSCDocsOptions fmt input) = do e <- P.parseModulesFromFiles (fromMaybe "") <$> mapM (fmap (first Just) . parseFile) (nub input) case e of Left err -> do hPutStrLn stderr $ show err exitFailure Right ms -> do- putStrLn . runDocs $ renderModules (map snd ms)+ case fmt of+ Markdown -> putStrLn . runDocs $ renderModules (map snd ms)+ Etags -> ldump $ dumpEtags $ pairs ms+ Ctags -> ldump $ dumpCtags $ pairs ms exitSuccess-+ where pairs :: [(Maybe String, m)] -> [(String, m)]+ pairs = map (\(k,m) -> (fromMaybe "" k,m))+ ldump :: [String] -> IO ()+ ldump = mapM_ putStrLn+ parseFile :: FilePath -> IO (FilePath, String) parseFile input = (,) input <$> readFile input @@ -86,9 +102,12 @@ mapM_ renderModule ms renderModule :: P.Module -> Docs-renderModule mdl@(P.Module moduleName _ exps) = do+renderModule mdl@(P.Module coms moduleName _ exps) = do headerLevel 2 $ "Module " ++ P.runModuleName moduleName spacer+ unless (null coms) $ do+ renderComments coms+ spacer renderTopLevel exps (P.exportedDeclarations mdl) spacer @@ -219,8 +238,20 @@ metavar "FILE" <> help "The input .purs file(s)" +instance Read Format where+ readsPrec _ "etags" = [(Etags, "")]+ readsPrec _ "ctags" = [(Ctags, "")]+ readsPrec _ "markdown" = [(Markdown, "")]+ readsPrec _ _ = [] ++format :: Parser Format+format = option auto $ value Markdown+ <> long "format"+ <> metavar "FORMAT"+ <> help "Set output FORMAT (markdown | etags | ctags)" + pscDocsOptions :: Parser PSCDocsOptions-pscDocsOptions = PSCDocsOptions <$> many inputFile+pscDocsOptions = PSCDocsOptions <$> format <*> many inputFile main :: IO () main = execParser opts >>= docgen
psc-make/Main.hs view
@@ -155,7 +155,7 @@ <*> noMagicDo <*> pure Nothing <*> noOpts- <*> comments+ <*> (not <$> comments) <*> verboseErrors <*> pure P.MakeOptions
psc/Main.hs view
@@ -180,7 +180,7 @@ <*> runMain <*> noOpts <*> verboseErrors- <*> comments+ <*> (not <$> comments) <*> additionalOptions where additionalOptions =
psci/Commands.hs view
@@ -32,7 +32,7 @@ -- | -- Import a module from a loaded file --- | Import ModuleName+ | Import ImportedModule -- | -- Browse a module --@@ -50,9 +50,9 @@ -- | Reset -- |- -- Binds a value to a name+ -- Add some declarations to the current evaluation context. --- | Let [Declaration]+ | Decls [Declaration] -- | -- Find the type of an expression --@@ -66,22 +66,13 @@ -- | Show String --- |--- The help menu.+-- | All of the data that is contained by an ImportDeclaration in the AST.+-- That is: ---help :: [(String, String, String)]-help =- [ (":?", "", "Show this help menu")- , (":i", "<module>", "Import <module> for use in PSCI")- , (":b", "<module>", "Browse <module>")- , (":m", "<file>", "Load <file> for importing")- , (":q", "", "Quit PSCi")- , (":r", "", "Reset")- , (":s", "import", "Show imported modules")- , (":s", "loaded", "Show loaded modules")- , (":t", "<expr>", "Show the type of <expr>")- , (":k", "<type>", "Show the kind of <type>")- ]--commands :: [String]-commands = map (\ (a, _, _) -> a) help+-- * A module name, the name of the module which is being imported+-- * An ImportDeclarationType which specifies whether there is an explicit+-- import list, a hiding list, or neither.+-- * If the module is imported qualified, its qualified name in the importing+-- module. Otherwise, Nothing.+--+type ImportedModule = (ModuleName, ImportDeclarationType, Maybe ModuleName)
psci/Main.hs view
@@ -54,12 +54,14 @@ import qualified Language.PureScript.Names as N import qualified Paths_purescript as Paths -import Commands as C+import qualified Commands as C+import qualified Directive as D import Parser data PSCiOptions = PSCiOptions- { psciMultiLineMode :: Bool+ { psciMultiLineMode :: Bool , psciInputFile :: [FilePath]+ , psciInputNodeFlags :: [String] } -- |@@ -70,11 +72,16 @@ -- data PSCiState = PSCiState { psciImportedFilenames :: [FilePath]- , psciImportedModuleNames :: [P.ModuleName]+ , psciImportedModules :: [C.ImportedModule] , psciLoadedModules :: [(Either P.RebuildPolicy FilePath, P.Module)] , psciLetBindings :: [P.Declaration]+ , psciNodeFlags :: [String] } +psciImportedModuleNames :: PSCiState -> [P.ModuleName]+psciImportedModuleNames (PSCiState{psciImportedModules = is}) =+ map (\(mn, _, _) -> mn) is+ -- State helpers -- |@@ -86,8 +93,8 @@ -- | -- Updates the state to have more imported modules. ---updateImports :: P.ModuleName -> PSCiState -> PSCiState-updateImports name st = st { psciImportedModuleNames = name : psciImportedModuleNames st }+updateImportedModules :: C.ImportedModule -> PSCiState -> PSCiState+updateImportedModules im st = st { psciImportedModules = im : psciImportedModules st } -- | -- Updates the state to have more loaded files.@@ -105,8 +112,8 @@ -- | -- Load the necessary modules. ---defaultImports :: [P.ModuleName]-defaultImports = [P.ModuleName [P.ProperName "Prelude"]]+defaultImports :: [C.ImportedModule]+defaultImports = [(P.ModuleName [P.ProperName "Prelude"], D.Implicit, Nothing)] -- | -- Locates the node executable.@@ -168,9 +175,17 @@ -- helpMessage :: String helpMessage = "The following commands are available:\n\n " ++- intercalate "\n " (map line C.help)- where line :: (String, String, String) -> String- line (cmd, arg, desc) = intercalate " " [cmd, arg, replicate (11 - length arg) ' ', desc]+ intercalate "\n " (map line D.help)+ where+ line :: (D.Directive, String, String) -> String+ line (dir, arg, desc) = intercalate " "+ [ cmd+ , replicate (11 - length cmd) ' '+ , arg+ , replicate (11 - length arg) ' '+ , desc+ ]+ where cmd = ":" ++ head (D.commands dir) -- | -- The welcome prologue.@@ -203,19 +218,23 @@ -- Decide what kind of completion we need based on input. completionContext :: String -> String -> Maybe CompletionContext completionContext cmd@"" _ = Just $ Multiple [Command cmd, Identifier]-completionContext cmd@(':' : _ ) _- | cmd `elem` C.commands || cmd == ":" = Just $ Command cmd-completionContext (':' : c : _) word = case c of- 'i' -> Just Module- 'b' -> Just Module- 'm' -> Just $ FilePath word- 'q' -> Nothing- 'r' -> Nothing- '?' -> Nothing- 's' -> Just $ Fixed ["import", "loaded"]- 't' -> Just Identifier- 'k' -> Just Type- _ -> Nothing+completionContext (':' : cmd) word =+ case D.parseDirective dstr of+ Just directive | dstr `elem` D.commands directive -> context directive+ _ -> Just $ Command cmd+ where+ dstr :: String+ dstr = takeWhile (not . isSpace) cmd++ context :: D.Directive -> Maybe CompletionContext+ context D.Browse = Just Module+ context D.Load = Just $ FilePath word+ context D.Quit = Nothing+ context D.Reset = Nothing+ context D.Help = Nothing+ context D.Show = Just $ Fixed ["import", "loaded"]+ context D.Type = Just Identifier+ context D.Kind = Just Type completionContext _ _ = Just Identifier -- |@@ -236,13 +255,16 @@ return $ sortBy sorter completions getCompletion :: CompletionContext -> StateT PSCiState IO [Either String Completion]- getCompletion (Command s) = return $ (map Left) $ nub $ filter (isPrefixOf s) C.commands getCompletion (FilePath f) = (map Right) <$> listFiles f getCompletion Module = (map Left) <$> getModuleNames getCompletion Identifier = (map Left) <$> ((++) <$> getIdentNames <*> getDctorNames) getCompletion Type = (map Left) <$> getTypeNames getCompletion (Fixed list) = return $ (map Left) list getCompletion (Multiple contexts) = concat <$> mapM getCompletion contexts+ getCompletion (Command cmd) = return . map (Left . (":" ++)) . nub $ matching+ where+ matching :: [String]+ matching = filter (isPrefixOf cmd) . concatMap (D.commands) $ D.directives getLoadedModules :: StateT PSCiState IO [P.Module] getLoadedModules = map snd . psciLoadedModules <$> get@@ -284,7 +306,7 @@ getTypeName _ = Nothing identNames :: P.Module -> [N.Ident]- identNames (P.Module _ ds exports) = nub [ ident | ident <- mapMaybe (getDeclName exports) (D.flattenDecls ds) ]+ identNames (P.Module _ _ ds exports) = nub [ ident | ident <- mapMaybe (getDeclName exports) (D.flattenDecls ds) ] where getDeclName :: Maybe [P.DeclarationRef] -> P.Declaration -> Maybe P.Ident getDeclName exts decl@(P.ValueDeclaration ident _ _ _) | P.isExported exts decl = Just ident getDeclName exts decl@(P.ExternDeclaration _ ident _ _) | P.isExported exts decl = Just ident@@ -305,7 +327,7 @@ onlyDataDecls = (filter P.isDataDecl (P.exportedDeclarations m)) moduleNames :: [P.Module] -> [String]- moduleNames ms = nub [show moduleName | P.Module moduleName _ _ <- ms]+ moduleNames ms = nub [show moduleName | P.Module _ moduleName _ _ <- ms] sorter :: Completion -> Completion -> Ordering sorter (Completion _ d1 _) (Completion _ d2 _) = if ":" `isPrefixOf` d1 then LT else compare d1 d2@@ -351,10 +373,9 @@ -- Makes a volatile module to execute the current expression. -- createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module-createTemporaryModule exec PSCiState{psciImportedModuleNames = imports, psciLetBindings = lets} val =+createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val = let moduleName = P.ModuleName [P.ProperName "$PSCI"]- importDecl m = P.ImportDeclaration m P.Unqualified Nothing traceModule = P.ModuleName [P.ProperName "Debug", P.ProperName "Trace"] trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print")) mainValue = P.App trace (P.Var (P.Qualified Nothing (P.Ident "it")))@@ -362,32 +383,33 @@ mainDecl = P.ValueDeclaration (P.Ident "main") P.Value [] $ Right mainValue decls = if exec then [itDecl, mainDecl] else [itDecl] in- P.Module moduleName ((importDecl `map` imports) ++ lets ++ decls) Nothing+ P.Module [] moduleName ((importDecl `map` imports) ++ lets ++ decls) Nothing -- | -- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration. -- createTemporaryModuleForKind :: PSCiState -> P.Type -> P.Module-createTemporaryModuleForKind PSCiState{psciImportedModuleNames = imports} typ =+createTemporaryModuleForKind PSCiState{psciImportedModules = imports} typ = let moduleName = P.ModuleName [P.ProperName "$PSCI"]- importDecl m = P.ImportDeclaration m P.Unqualified Nothing itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ in- P.Module moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing+ P.Module [] moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing -- | -- Makes a volatile module to execute the current imports. -- createTemporaryModuleForImports :: PSCiState -> P.Module-createTemporaryModuleForImports PSCiState{psciImportedModuleNames = imports} =+createTemporaryModuleForImports PSCiState{psciImportedModules = imports} = let moduleName = P.ModuleName [P.ProperName "$PSCI"]- importDecl m = P.ImportDeclaration m P.Unqualified Nothing in- P.Module moduleName (importDecl `map` imports) Nothing+ P.Module [] moduleName (importDecl `map` imports) Nothing +importDecl :: C.ImportedModule -> P.Declaration+importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ+ modulesDir :: FilePath modulesDir = ".psci_modules" ++ pathSeparator : "node_modules" @@ -401,24 +423,25 @@ handleDeclaration val = do st <- PSCI $ lift get let m = createTemporaryModule True st val+ let nodeArgs = psciNodeFlags st ++ [indexFile] e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) [] case e of Left err -> PSCI $ outputStrLn err Right _ -> do psciIO $ writeFile indexFile "require('$PSCI').main();" process <- psciIO findNodeProcess- result <- psciIO $ traverse (\node -> readProcessWithExitCode node [indexFile] "") process+ result <- psciIO $ traverse (\node -> readProcessWithExitCode node nodeArgs "") process case result of Just (ExitSuccess, out, _) -> PSCI $ outputStrLn out Just (ExitFailure _, _, err) -> PSCI $ outputStrLn err Nothing -> PSCI $ outputStrLn "Couldn't find node.js" -- |--- Takes a let declaration and updates the environment, then run a make. If the declaration fails,--- restore the pre-let environment.+-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,+-- restore the original environment. ---handleLet :: [P.Declaration] -> PSCI ()-handleLet ds = do+handleDecls :: [P.Declaration] -> PSCI ()+handleDecls ds = do st <- PSCI $ lift get let st' = updateLets ds st let m = createTemporaryModule False st' (P.ObjectLiteral [])@@ -436,24 +459,44 @@ psciIO $ readModules loadedModules >>= putStrLn return () where readModules = return . unlines . sort . nub . map toModuleName- toModuleName = N.runModuleName . (\ (D.Module mdName _ _) -> mdName) . snd+ toModuleName = N.runModuleName . (\ (D.Module _ mdName _ _) -> mdName) . snd -- | -- Show the imported modules in psci. -- handleShowImportedModules :: PSCI () handleShowImportedModules = do- PSCiState { psciImportedModuleNames = importedModuleNames } <- PSCI $ lift get- psciIO $ readModules importedModuleNames >>= putStrLn+ PSCiState { psciImportedModules = importedModules } <- PSCI $ lift get+ psciIO $ showModules importedModules >>= putStrLn return ()- where readModules = return . unlines . sort . map N.runModuleName+ where+ showModules = return . unlines . sort . map showModule+ showModule (mn, declType, asQ) =+ "import " ++ case asQ of+ Just mn' -> "qualified " ++ N.runModuleName mn ++ " as " ++ N.runModuleName mn'+ Nothing -> N.runModuleName mn ++ " " ++ showDeclType declType + showDeclType D.Implicit = ""+ showDeclType (D.Explicit refs) = refsList refs+ showDeclType (D.Hiding refs) = "hiding " ++ refsList refs+ refsList refs = "(" ++ commaList (map showRef refs) ++ ")"++ showRef :: P.DeclarationRef -> String+ showRef (D.TypeRef pn dctors) = show pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"+ showRef (D.ValueRef ident) = show ident+ showRef (D.TypeClassRef pn) = show pn+ showRef (D.TypeInstanceRef ident) = show ident+ showRef (D.PositionedDeclarationRef _ _ ref) = showRef ref++ commaList :: [String] -> String+ commaList = intercalate ", "+ -- | -- Imports a module, preserving the initial state on failure. ---handleImport :: P.ModuleName -> PSCI ()-handleImport moduleName = do- st <- updateImports moduleName <$> PSCI (lift get)+handleImport :: C.ImportedModule -> PSCI ()+handleImport im = do+ st <- updateImportedModules im <$> PSCI (lift get) let m = createTemporaryModuleForImports st e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) [] case e of@@ -507,7 +550,7 @@ case env of Left err -> PSCI $ outputStrLn err Right env' ->- if moduleName `notElem` (nub . map ((\ (P.Module modName _ _ ) -> modName) . snd)) loadedModules+ if moduleName `notElem` (nub . map ((\ (P.Module _ modName _ _ ) -> modName) . snd)) loadedModules then PSCI $ outputStrLn $ "Module '" ++ N.runModuleName moduleName ++ "' is not valid." else printModuleSignatures moduleName env' @@ -528,7 +571,7 @@ let chk = P.CheckState env' 0 0 (Just mName) k = L.runStateT (P.unCheck (P.kindOf mName typ')) chk case k of- Left errStack -> PSCI . outputStrLn . P.prettyPrintErrorStack False $ errStack+ Left errStack -> PSCI . outputStrLn . P.prettyPrintMultipleErrors False $ errStack Right (kind, _) -> PSCI . outputStrLn . P.prettyPrintKind $ kind Nothing -> PSCI $ outputStrLn "Could not find kind" @@ -537,7 +580,7 @@ -- | -- Parses the input and returns either a Metacommand or an expression. ---getCommand :: Bool -> InputT (StateT PSCiState IO) (Either String (Maybe Command))+getCommand :: Bool -> InputT (StateT PSCiState IO) (Either String (Maybe C.Command)) getCommand singleLineMode = do firstLine <- getInputLine "> " case firstLine of@@ -552,12 +595,12 @@ -- | -- Performs an action for each meta-command given, and also for expressions.. ---handleCommand :: Command -> PSCI ()-handleCommand (Expression val) = handleDeclaration val-handleCommand Help = PSCI $ outputStrLn helpMessage-handleCommand (Import moduleName) = handleImport moduleName-handleCommand (Let l) = handleLet l-handleCommand (LoadFile filePath) = do+handleCommand :: C.Command -> PSCI ()+handleCommand (C.Expression val) = handleDeclaration val+handleCommand C.Help = PSCI $ outputStrLn helpMessage+handleCommand (C.Import im) = handleImport im+handleCommand (C.Decls l) = handleDecls l+handleCommand (C.LoadFile filePath) = do absPath <- psciIO $ expandTilde filePath exists <- psciIO $ doesFileExist absPath if exists then do@@ -568,22 +611,22 @@ Right mods -> PSCI . lift $ modify (updateModules (map ((,) (Right absPath)) mods)) else PSCI . outputStrLn $ "Couldn't locate: " ++ filePath-handleCommand Reset = do+handleCommand C.Reset = do files <- psciImportedFilenames <$> PSCI (lift get) PSCI . lift . modify $ \st -> st { psciImportedFilenames = files- , psciImportedModuleNames = defaultImports+ , psciImportedModules = defaultImports , psciLetBindings = [] } loadAllImportedModules-handleCommand (TypeOf val) = handleTypeOf val-handleCommand (KindOf typ) = handleKindOf typ-handleCommand (Browse moduleName) = handleBrowse moduleName-handleCommand (Show "loaded") = handleShowLoadedModules-handleCommand (Show "import") = handleShowImportedModules+handleCommand (C.TypeOf val) = handleTypeOf val+handleCommand (C.KindOf typ) = handleKindOf typ+handleCommand (C.Browse moduleName) = handleBrowse moduleName+handleCommand (C.Show "loaded") = handleShowLoadedModules+handleCommand (C.Show "import") = handleShowImportedModules handleCommand _ = PSCI $ outputStrLn "Unknown command" -loadUserConfig :: IO (Maybe [Command])+loadUserConfig :: IO (Maybe [C.Command]) loadUserConfig = do configFile <- (</> ".psci") <$> getCurrentDirectory exists <- doesFileExist configFile@@ -608,7 +651,7 @@ Right modules -> do historyFilename <- getHistoryFilename let settings = defaultSettings { historyFile = Just historyFilename }- flip evalStateT (PSCiState psciInputFile defaultImports modules []) . runInputT (setComplete completion settings) $ do+ flip evalStateT (PSCiState psciInputFile defaultImports modules [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do outputStrLn prologueMessage traverse_ (mapM_ (runPSCI . handleCommand)) config go@@ -619,7 +662,7 @@ case c of Left err -> outputStrLn err >> go Right Nothing -> go- Right (Just Quit) -> outputStrLn quitMessage+ Right (Just C.Quit) -> outputStrLn quitMessage Right (Just c') -> runPSCI (loadAllImportedModules >> handleCommand c') >> go multiLineMode :: Parser Bool@@ -633,9 +676,19 @@ metavar "FILE" <> Opts.help "Optional .purs files to load on start" +nodeFlagsFlag :: Parser [String]+nodeFlagsFlag = option parser $+ long "node-opts"+ <> metavar "NODE_OPTS"+ <> value []+ <> Opts.help "Flags to pass to node, separated by spaces"+ where+ parser = words <$> str+ psciOptions :: Parser PSCiOptions psciOptions = PSCiOptions <$> multiLineMode <*> many inputFile+ <*> nodeFlagsFlag main :: IO () main = execParser opts >>= loop
psci/Parser.hs view
@@ -13,13 +13,14 @@ -- ----------------------------------------------------------------------------- -module Parser (- parseCommand+module Parser+ ( parseCommand ) where import Prelude hiding (lex) -import Commands+import qualified Commands as C+import qualified Directive as D import Data.Char (isSpace) @@ -33,50 +34,92 @@ -- | -- Parses PSCI metacommands or expressions input from the user. ---parseCommand :: String -> Either String Command+parseCommand :: String -> Either String C.Command parseCommand cmdString =- case splitCommand cmdString of- Just ('?', _) -> return Help- Just ('q', _) -> return Quit- Just ('r', _) -> return Reset- Just ('i', moduleName) -> Import <$> parseRest P.moduleName moduleName- Just ('b', moduleName) -> Browse <$> parseRest P.moduleName moduleName- Just ('m', filename) -> return $ LoadFile (trimEnd filename)- Just ('s', command) -> return $ Show (trimEnd command)- Just ('t', expr) -> TypeOf <$> parseRest P.parseValue expr- Just ('k', ty) -> KindOf <$> parseRest P.parseType ty- Just _ -> Left $ "Unrecognized command. Type :? for help."- Nothing -> parseRest (psciLet <|> psciExpression) cmdString+ case cmdString of+ (':' : cmd) -> parseDirective cmd+ _ -> parseRest psciCommand cmdString++parseRest :: P.TokenParser a -> String -> Either String a+parseRest p s = either (Left . show) Right $ do+ ts <- P.lex "" s+ P.runTokenParser "" (p <* eof) ts++psciCommand :: P.TokenParser C.Command+psciCommand = choice (map try parsers) where- parseRest :: P.TokenParser a -> String -> Either String a- parseRest p s = either (Left . show) Right $ do- ts <- P.lex "" s- P.runTokenParser "" (p <* eof) ts+ parsers =+ [ psciLet+ , psciImport+ , psciOtherDeclaration+ , psciExpression+ ] - trimEnd :: String -> String- trimEnd = reverse . dropWhile isSpace . reverse+trim :: String -> String+trim = trimEnd . trimStart - -- |- -- Split a command into a command char and the trailing string- --- splitCommand :: String -> Maybe (Char, String)- splitCommand (':' : c : s) = Just (c, dropWhile isSpace s)- splitCommand _ = Nothing+trimStart :: String -> String+trimStart = dropWhile isSpace - -- |- -- Parses expressions entered at the PSCI repl.- --- psciExpression :: P.TokenParser Command- psciExpression = Expression <$> P.parseValue+trimEnd :: String -> String+trimEnd = reverse . trimStart . reverse - -- |- -- PSCI version of @let@.- -- This is essentially let from do-notation.- -- However, since we don't support the @Eff@ monad,- -- we actually want the normal @let@.- --- psciLet :: P.TokenParser Command- psciLet = Let <$> (P.reserved "let" *> P.indented *> manyDecls)- where- manyDecls :: P.TokenParser [P.Declaration]- manyDecls = C.mark (many1 (C.same *> P.parseDeclaration))+parseDirective :: String -> Either String C.Command+parseDirective cmd =+ case D.parseDirective dstr of+ Just D.Help -> return C.Help+ Just D.Quit -> return C.Quit+ Just D.Reset -> return C.Reset+ Just D.Browse -> C.Browse <$> parseRest P.moduleName arg+ Just D.Load -> return $ C.LoadFile (trim arg)+ Just D.Show -> return $ C.Show (trim arg)+ Just D.Type -> C.TypeOf <$> parseRest P.parseValue arg+ Just D.Kind -> C.KindOf <$> parseRest P.parseType arg+ Nothing -> Left $ "Unrecognized command. Type :? for help."+ where (dstr, arg) = break isSpace cmd++-- |+-- Parses expressions entered at the PSCI repl.+--+psciExpression :: P.TokenParser C.Command+psciExpression = C.Expression <$> P.parseValue++-- |+-- PSCI version of @let@.+-- This is essentially let from do-notation.+-- However, since we don't support the @Eff@ monad,+-- we actually want the normal @let@.+--+psciLet :: P.TokenParser C.Command+psciLet = C.Decls <$> (P.reserved "let" *> P.indented *> manyDecls)+ where+ manyDecls :: P.TokenParser [P.Declaration]+ manyDecls = C.mark (many1 (C.same *> P.parseLocalDeclaration))++-- | Imports must be handled separately from other declarations, so that+-- :show import works, for example.+psciImport :: P.TokenParser C.Command+psciImport = C.Import <$> P.parseImportDeclaration'++-- | Any other declaration that we don't need a 'special case' parser for+-- (like let or import declarations).+psciOtherDeclaration :: P.TokenParser C.Command+psciOtherDeclaration = C.Decls . (:[]) <$> do+ decl <- discardPositionInfo <$> P.parseDeclaration+ if acceptable decl+ then return decl+ else fail "this kind of declaration is not supported in psci"++discardPositionInfo :: P.Declaration -> P.Declaration+discardPositionInfo (P.PositionedDeclaration _ _ d) = d+discardPositionInfo d = d++acceptable :: P.Declaration -> Bool+acceptable (P.DataDeclaration _ _ _ _) = True+acceptable (P.TypeSynonymDeclaration _ _ _) = True+acceptable (P.ExternDeclaration _ _ _ _) = True+acceptable (P.ExternDataDeclaration _ _) = True+acceptable (P.ExternInstanceDeclaration _ _ _ _) = True+acceptable (P.TypeClassDeclaration _ _ _ _) = True+acceptable (P.TypeInstanceDeclaration _ _ _ _ _) = True+acceptable _ = False
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.6.8+version: 0.6.9 cabal-version: >=1.8 build-type: Simple license: MIT@@ -35,7 +35,8 @@ utf8-string >= 1 && < 2, pattern-arrows >= 0.0.2 && < 0.1, file-embed >= 0.0.7 && < 0.0.8,- time -any+ time -any,+ boxes >= 0.1.4 && < 0.2.0 exposed-modules: Language.PureScript Language.PureScript.AST Language.PureScript.AST.Binders@@ -96,7 +97,6 @@ Language.PureScript.Sugar.Operators Language.PureScript.Sugar.TypeClasses Language.PureScript.Sugar.TypeDeclarations- Language.PureScript.Supply Language.PureScript.Traversals Language.PureScript.TypeChecker Language.PureScript.TypeChecker.Entailment@@ -112,6 +112,8 @@ Language.PureScript.Types Control.Monad.Unify+ Control.Monad.Supply+ Control.Monad.Supply.Class exposed: True buildable: True hs-source-dirs: src
+ src/Control/Monad/Supply.hs view
@@ -0,0 +1,43 @@+-----------------------------------------------------------------------------+--+-- Module : Control.Monad.Supply+-- Copyright : (c) Phil Freeman 2014+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+-- Fresh variable supply+--+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Control.Monad.Supply where++import Data.Functor.Identity++import Control.Applicative+import Control.Monad.State+import Control.Monad.Except+import Control.Monad.Reader+import Control.Monad.Writer++newtype SupplyT m a = SupplyT { unSupplyT :: StateT Integer m a } + deriving (Functor, Applicative, Monad, MonadTrans, MonadError e, MonadWriter w, MonadReader r)++runSupplyT :: Integer -> SupplyT m a -> m (a, Integer)+runSupplyT n = flip runStateT n . unSupplyT++evalSupplyT :: (Functor m) => Integer -> SupplyT m a -> m a+evalSupplyT n = fmap fst . runSupplyT n++type Supply = SupplyT Identity++runSupply :: Integer -> Supply a -> (a, Integer)+runSupply n = runIdentity . runSupplyT n++evalSupply :: Integer -> Supply a -> a+evalSupply n = runIdentity . evalSupplyT n
+ src/Control/Monad/Supply/Class.hs view
@@ -0,0 +1,36 @@+-----------------------------------------------------------------------------+--+-- Module : Control.Monad.Supply.Class+-- Copyright : (c) PureScript 2015+-- License : MIT+--+-- Maintainer : Phil Freeman <paf31@cantab.net>+-- Stability : experimental+-- Portability :+--+-- |+-- A class for monads supporting a supply of fresh names+--+-----------------------------------------------------------------------------++{-# LANGUAGE MultiParamTypeClasses #-}++module Control.Monad.Supply.Class where++import Control.Monad.Supply+import Control.Monad.State++class (Monad m) => MonadSupply m where+ fresh :: m Integer+ +instance (Monad m) => MonadSupply (SupplyT m) where+ fresh = SupplyT $ do+ n <- get+ put (n + 1)+ return n+ +instance (MonadSupply m) => MonadSupply (StateT s m) where+ fresh = lift fresh++freshName :: (MonadSupply m) => m String+freshName = liftM (('_' :) . show) fresh
src/Control/Monad/Unify.hs view
@@ -20,11 +20,9 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE OverloadedStrings #-} module Control.Monad.Unify where -import Data.String (IsString) import Data.Monoid import Control.Applicative@@ -85,9 +83,15 @@ defaultUnifyState = UnifyState 0 mempty -- |+-- A class for errors which support unification errors+--+class UnificationError t e where+ occursCheckFailed :: t -> e++-- | -- The type checking monad, which provides the state of the type checker, and error reporting capabilities ---newtype UnifyT t m a = UnifyT { unUnify :: (StateT (UnifyState t) m) a }+newtype UnifyT t m a = UnifyT { unUnify :: StateT (UnifyState t) m a } deriving (Functor, Monad, Applicative, Alternative, MonadPlus) instance (MonadState s m) => MonadState s (UnifyT t m) where@@ -113,7 +117,7 @@ -- | -- Replace a unification variable with the specified value in the current substitution ---(=:=) :: (IsString e, Monad m, MonadError e m, Unifiable m t) => Unknown -> t -> UnifyT t m ()+(=:=) :: (UnificationError t e, Monad m, MonadError e m, Unifiable m t) => Unknown -> t -> UnifyT t m () (=:=) u t' = do st <- UnifyT get let sub = unifyCurrentSubstitution st@@ -128,10 +132,10 @@ -- | -- Perform the occurs check, to make sure a unification variable does not occur inside a value ---occursCheck :: (IsString e, Monad m, MonadError e m, Partial t) => Unknown -> t -> UnifyT t m ()+occursCheck :: (UnificationError t e, Monad m, MonadError e m, Partial t) => Unknown -> t -> UnifyT t m () occursCheck u t = case isUnknown t of- Nothing -> when (u `elem` unknowns t) $ UnifyT . lift . throwError $ "Occurs check fails"+ Nothing -> when (u `elem` unknowns t) $ UnifyT . lift . throwError $ occursCheckFailed t _ -> return () -- |
src/Language/PureScript.hs view
@@ -13,15 +13,29 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE DataKinds, QuasiQuotes, TemplateHaskell, FlexibleContexts #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-} -module Language.PureScript (module P, compile, compile', RebuildPolicy(..), MonadMake(..), make, prelude) where+module Language.PureScript+ ( module P+ , compile+ , compile'+ , RebuildPolicy(..)+ , MonadMake(..)+ , make+ , prelude+ , version+ ) where import Data.FileEmbed (embedFile) import Data.Function (on) import Data.List (sortBy, groupBy, intercalate) import Data.Maybe (fromMaybe) import Data.Time.Clock+import Data.Version (Version) import qualified Data.Traversable as T (traverse) import qualified Data.ByteString.UTF8 as BU import qualified Data.Map as M@@ -48,12 +62,14 @@ import Language.PureScript.Pretty as P import Language.PureScript.Renamer as P import Language.PureScript.Sugar as P-import Language.PureScript.Supply as P+import Control.Monad.Supply as P import Language.PureScript.TypeChecker as P import Language.PureScript.Types as P import qualified Language.PureScript.CoreFn as CoreFn import qualified Language.PureScript.Constants as C +import qualified Paths_purescript as Paths+ -- | -- Compile a collection of modules --@@ -84,15 +100,15 @@ additional <- asks optionsAdditional mainModuleIdent <- asks (fmap moduleNameFromString . optionsMain) (sorted, _) <- sortModules $ map importPrim $ if noPrelude then ms else map importPrelude ms- (desugared, nextVar) <- stringifyErrorStack True $ runSupplyT 0 $ desugar sorted+ (desugared, nextVar) <- interpretMultipleErrors True $ runSupplyT 0 $ desugar sorted (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent- regrouped <- stringifyErrorStack True $ createBindingGroupsModule . collapseBindingGroupsModule $ elaborated+ regrouped <- interpretMultipleErrors True $ createBindingGroupsModule . collapseBindingGroupsModule $ elaborated let corefn = map (CoreFn.moduleToCoreFn env') regrouped let entryPoints = moduleNameFromString `map` entryPointModules additional let elim = if null entryPoints then corefn else eliminateDeadCode entryPoints corefn let renamed = renameInModules elim let codeGenModuleNames = moduleNameFromString `map` codeGenModules additional- let modulesToCodeGen = if null codeGenModuleNames then renamed else filter (\(CoreFn.Module mn _ _ _ _) -> mn `elem` codeGenModuleNames) renamed+ let modulesToCodeGen = if null codeGenModuleNames then renamed else filter (\(CoreFn.Module _ mn _ _ _ _) -> mn `elem` codeGenModuleNames) renamed js <- concat <$> (evalSupplyT nextVar $ T.traverse moduleToJs modulesToCodeGen) let exts = intercalate "\n" . map (`moduleToPs` env') $ regrouped js' <- generateMain env' js@@ -154,15 +170,15 @@ -- If timestamps have not changed, the externs file can be used to provide the module's types without -- having to typecheck the module again. ---make :: (Functor m, Applicative m, Monad m, MonadMake m)+make :: forall m. (Functor m, Applicative m, Monad m, MonadMake m) => FilePath -> [(Either RebuildPolicy FilePath, Module)] -> [String] -> m Environment make outputDir ms prefix = do noPrelude <- asks optionsNoPrelude- let filePathMap = M.fromList (map (\(fp, Module mn _ _) -> (mn, fp)) ms)+ let filePathMap = M.fromList (map (\(fp, Module _ mn _ _) -> (mn, fp)) ms) (sorted, graph) <- sortModules $ map importPrim $ if noPrelude then map snd ms else map (importPrelude . snd) ms - toRebuild <- foldM (\s (Module moduleName' _ _) -> do+ toRebuild <- foldM (\s (Module _ moduleName' _ _) -> do let filePath = runModuleName moduleName' jsFile = outputDir </> filePath </> "index.js"@@ -180,30 +196,29 @@ marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted - (desugared, nextVar) <- stringifyErrorStack True $ runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)+ (desugared, nextVar) <- interpretMultipleErrors True $ runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked) evalSupplyT nextVar $ go initEnvironment desugared where- go :: (Functor m, Applicative m, Monad m, MonadMake m)- => Environment -> [(Bool, Module)] -> SupplyT m Environment+ go :: Environment -> [(Bool, Module)] -> SupplyT m Environment go env [] = return env go env ((False, m) : ms') = do (_, env') <- lift . runCheck' env $ typeCheckModule Nothing m go env' ms'- go env ((True, m@(Module moduleName' _ exps)) : ms') = do+ go env ((True, m@(Module coms moduleName' _ exps)) : ms') = do let filePath = runModuleName moduleName' jsFile = outputDir </> filePath </> "index.js" externsFile = outputDir </> filePath </> "externs.purs" lift . progress $ "Compiling " ++ runModuleName moduleName' - (Module _ elaborated _, env') <- lift . runCheck' env $ typeCheckModule Nothing m+ (Module _ _ elaborated _, env') <- lift . runCheck' env $ typeCheckModule Nothing m - regrouped <- stringifyErrorStack True . createBindingGroups moduleName' . collapseBindingGroups $ elaborated+ regrouped <- interpretMultipleErrors True . createBindingGroups moduleName' . collapseBindingGroups $ elaborated - let mod' = Module moduleName' regrouped exps+ let mod' = Module coms moduleName' regrouped exps let corefn = CoreFn.moduleToCoreFn env' mod' let [renamed] = renameInModules [corefn] @@ -216,18 +231,18 @@ go env' ms' - rebuildIfNecessary :: (Functor m, Monad m, MonadMake m) => M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)]+ rebuildIfNecessary :: M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)] rebuildIfNecessary _ _ [] = return []- rebuildIfNecessary graph toRebuild (m@(Module moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do+ rebuildIfNecessary graph toRebuild (m@(Module _ moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do let deps = fromMaybe [] $ moduleName' `M.lookup` graph toRebuild' = toRebuild `S.union` S.fromList deps (:) (True, m) <$> rebuildIfNecessary graph toRebuild' ms'- rebuildIfNecessary graph toRebuild (Module moduleName' _ _ : ms') = do+ rebuildIfNecessary graph toRebuild (Module _ moduleName' _ _ : ms') = do let externsFile = outputDir </> runModuleName moduleName' </> "externs.purs" externs <- readTextFile externsFile externsModules <- fmap (map snd) . either (throwError . show) return $ P.parseModulesFromFiles id [(externsFile, externs)] case externsModules of- [m'@(Module moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'+ [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms' _ -> throwError $ "Externs file " ++ externsFile ++ " was invalid" reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName]@@ -240,9 +255,9 @@ -- Add an import declaration for a module if it does not already explicitly import it. -- addDefaultImport :: ModuleName -> Module -> Module-addDefaultImport toImport m@(Module mn decls exps) =+addDefaultImport toImport m@(Module coms mn decls exps) = if isExistingImport `any` decls || mn == toImport then m- else Module mn (ImportDeclaration toImport Unqualified Nothing : decls) exps+ else Module coms mn (ImportDeclaration toImport Implicit Nothing : decls) exps where isExistingImport (ImportDeclaration mn' _ _) | mn' == toImport = True isExistingImport (PositionedDeclaration _ _ d) = isExistingImport d@@ -256,3 +271,6 @@ prelude :: String prelude = BU.toString $(embedFile "prelude/prelude.purs")++version :: Version+version = Paths.version
src/Language/PureScript/AST/Declarations.hs view
@@ -30,14 +30,15 @@ import Language.PureScript.Environment -- |--- A module declaration, consisting of a module name, a list of declarations, and a list of the--- declarations that are explicitly exported. If the export list is Nothing, everything is exported.+-- A module declaration, consisting of comments about the module, a module name,+-- a list of declarations, and a list of the declarations that are+-- explicitly exported. If the export list is Nothing, everything is exported. ---data Module = Module ModuleName [Declaration] (Maybe [DeclarationRef]) deriving (Show, D.Data, D.Typeable)+data Module = Module [Comment] ModuleName [Declaration] (Maybe [DeclarationRef]) deriving (Show, D.Data, D.Typeable) -- | Return a module's name. getModuleName :: Module -> ModuleName-getModuleName (Module name _ _) = name+getModuleName (Module _ name _ _) = name -- | -- Test if a declaration is exported, given a module's export list.@@ -60,7 +61,7 @@ matches _ _ = False exportedDeclarations :: Module -> [Declaration]-exportedDeclarations (Module _ decls exps) = filter (isExported exps) (flattenDecls decls)+exportedDeclarations (Module _ _ decls exps) = filter (isExported exps) (flattenDecls decls) -- | -- Test if a data constructor for a given type is exported, given a module's export list.@@ -78,7 +79,7 @@ -- Return the exported data constructors for a given type. -- exportedDctors :: Module -> ProperName -> [ProperName]-exportedDctors (Module _ decls exps) ident =+exportedDctors (Module _ _ decls exps) ident = filter (isDctorExported ident exps) dctors where dctors = concatMap getDctors (flattenDecls decls)@@ -126,15 +127,15 @@ -- data ImportDeclarationType -- |- -- Unqualified import+ -- An import with no explicit list: `import M` --- = Unqualified+ = Implicit -- |- -- Qualified import with a list of references to import+ -- An import with an explicit list of references to import: `import M (foo)` --- | Qualifying [DeclarationRef]+ | Explicit [DeclarationRef] -- |- -- Import with hiding clause with a list of references to hide+ -- An import with a list of references to hide: `import M hiding (foo)` -- | Hiding [DeclarationRef] deriving (Show, D.Data, D.Typeable)@@ -260,11 +261,18 @@ isExternDecl _ = False -- |--- Test if a declaration is a type class or instance declaration+-- Test if a declaration is a type class instance declaration --+isTypeClassInstanceDeclaration :: Declaration -> Bool+isTypeClassInstanceDeclaration TypeInstanceDeclaration{} = True+isTypeClassInstanceDeclaration (PositionedDeclaration _ _ d) = isTypeClassInstanceDeclaration d+isTypeClassInstanceDeclaration _ = False++-- |+-- Test if a declaration is a type class declaration+-- isTypeClassDeclaration :: Declaration -> Bool isTypeClassDeclaration TypeClassDeclaration{} = True-isTypeClassDeclaration TypeInstanceDeclaration{} = True isTypeClassDeclaration (PositionedDeclaration _ _ d) = isTypeClassDeclaration d isTypeClassDeclaration _ = False
src/Language/PureScript/AST/SourcePos.hs view
@@ -30,7 +30,7 @@ -- Column number -- , sourcePosColumn :: Int- } deriving (D.Data, D.Typeable)+ } deriving (Eq, D.Data, D.Typeable) instance Show SourcePos where show sp = "line " ++ show (sourcePosLine sp) ++ ", column " ++ show (sourcePosColumn sp)@@ -47,7 +47,7 @@ -- End of the span -- , spanEnd :: SourcePos- } deriving (D.Data, D.Typeable)+ } deriving (Eq, D.Data, D.Typeable) instance Show SourceSpan where show sp = spanName sp ++ " " ++ show (spanStart sp) ++ " - " ++ show (spanEnd sp)
src/Language/PureScript/CodeGen/Externs.hs view
@@ -36,8 +36,8 @@ -- Generate foreign imports for all declarations in a module -- moduleToPs :: Module -> Environment -> String-moduleToPs (Module _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"-moduleToPs (Module moduleName ds (Just exts)) env = intercalate "\n" . execWriter $ do+moduleToPs (Module _ _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"+moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWriter $ do tell [ "module " ++ runModuleName moduleName ++ " where"] mapM_ declToPs ds mapM_ exportToPs exts
src/Language/PureScript/CodeGen/JS.hs view
@@ -13,7 +13,10 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE GADTs, ViewPatterns, FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-} module Language.PureScript.CodeGen.JS ( module AST,@@ -28,7 +31,8 @@ import Control.Applicative import Control.Arrow ((&&&)) import Control.Monad (foldM, replicateM, forM)-import Control.Monad.Reader (MonadReader, asks, lift)+import Control.Monad.Reader (MonadReader, asks)+import Control.Monad.Supply.Class import Language.PureScript.CodeGen.JS.AST as AST import Language.PureScript.CodeGen.JS.Common as Common@@ -36,7 +40,6 @@ import Language.PureScript.Names import Language.PureScript.CodeGen.JS.Optimizer import Language.PureScript.Options-import Language.PureScript.Supply import Language.PureScript.Traversals (sndM) import qualified Language.PureScript.Constants as C @@ -44,320 +47,313 @@ -- Generate code in the simplified Javascript intermediate representation for all declarations in a -- module. ---moduleToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => Module Ann -> SupplyT m [JS]-moduleToJs (Module name imps exps foreigns decls) = do- additional <- lift $ asks optionsAdditional- jsImports <- lift . T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [name]) $ imps+moduleToJs :: forall m mode. (Applicative m, Monad m, MonadReader (Options mode) m, MonadSupply m)+ => Module Ann -> m [JS]+moduleToJs (Module coms mn imps exps foreigns decls) = do+ additional <- asks optionsAdditional+ jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps let foreigns' = mapMaybe (\(_, js, _) -> js) foreigns- jsDecls <- mapM (bindToJs name) decls- optimized <- lift $ T.traverse (T.traverse optimize) jsDecls+ jsDecls <- mapM bindToJs decls+ optimized <- T.traverse (T.traverse optimize) jsDecls let isModuleEmpty = null exps- let moduleBody = JSStringLiteral "use strict" : jsImports ++ foreigns' ++ concat optimized+ comments <- not <$> asks optionsNoComments+ let strict = JSStringLiteral "use strict"+ let header = if comments && not (null coms) then JSComment coms strict else strict+ let moduleBody = header : jsImports ++ foreigns' ++ concat optimized let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) exps return $ case additional of MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps'] CompileOptions ns _ _ | not isModuleEmpty -> [ JSVariableIntroduction ns (Just (JSBinary Or (JSVar ns) (JSObjectLiteral [])) )- , JSAssignment (JSAccessor (moduleNameToJs name) (JSVar ns))+ , JSAssignment (JSAccessor (moduleNameToJs mn) (JSVar ns)) (JSApp (JSFunction Nothing [] (JSBlock (moduleBody ++ [JSReturn exps']))) []) ] _ -> [] --- |--- Generates Javascript code for a module import.----importToJs :: (Monad m, MonadReader (Options mode) m) => ModuleName -> m JS-importToJs mn = do- additional <- asks optionsAdditional- let moduleBody = case additional of- MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn)]- CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn) (JSVar ns)- return $ JSVariableIntroduction (moduleNameToJs mn) (Just moduleBody)+ where --- |--- Generate code in the simplified Javascript intermediate representation for a declaration----bindToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> Bind Ann -> SupplyT m [JS]-bindToJs mp (NonRec ident val) = return <$> nonRecToJS mp ident val-bindToJs mp (Rec vals) = forM vals (uncurry (nonRecToJS mp))+ -- |+ -- Generates Javascript code for a module import.+ --+ importToJs :: ModuleName -> m JS+ importToJs mn' = do+ additional <- asks optionsAdditional+ let moduleBody = case additional of+ MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn')]+ CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn') (JSVar ns)+ return $ JSVariableIntroduction (moduleNameToJs mn') (Just moduleBody) --- |--- Generate code in the simplified Javascript intermediate representation for a single non-recursive--- declaration.------ The main purpose of this function is to handle code generation for comments.----nonRecToJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> Ident -> Expr Ann -> SupplyT m JS-nonRecToJS m i e@(extractAnn -> (_, com, _, _)) | not (null com) = do- withoutComment <- lift $ asks optionsNoComments- if withoutComment- then nonRecToJS m i (modifyAnn removeComments e)- else JSComment com <$> nonRecToJS m i (modifyAnn removeComments e)-nonRecToJS mp ident val = do- js <- valueToJs mp val- return $ JSVariableIntroduction (identToJs ident) (Just js)+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a declaration+ --+ bindToJs :: Bind Ann -> m [JS]+ bindToJs (NonRec ident val) = return <$> nonRecToJS ident val+ bindToJs (Rec vals) = forM vals (uncurry nonRecToJS) + -- |+ -- Generate code in the simplified Javascript intermediate representation for a single non-recursive+ -- declaration.+ --+ -- The main purpose of this function is to handle code generation for comments.+ --+ nonRecToJS :: Ident -> Expr Ann -> m JS+ nonRecToJS i e@(extractAnn -> (_, com, _, _)) | not (null com) = do+ withoutComment <- asks optionsNoComments+ if withoutComment+ then nonRecToJS i (modifyAnn removeComments e)+ else JSComment com <$> nonRecToJS i (modifyAnn removeComments e)+ nonRecToJS ident val = do+ js <- valueToJs val+ return $ JSVariableIntroduction (identToJs ident) (Just js) --- |--- Generate code in the simplified Javascript intermediate representation for a variable based on a--- PureScript identifier.----var :: Ident -> JS-var = JSVar . identToJs+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a variable based on a+ -- PureScript identifier.+ --+ var :: Ident -> JS+ var = JSVar . identToJs --- |--- Generate code in the simplified Javascript intermediate representation for an accessor based on--- a PureScript identifier. If the name is not valid in Javascript (symbol based, reserved name) an--- indexer is returned.----accessor :: Ident -> JS -> JS-accessor (Ident prop) = accessorString prop-accessor (Op op) = JSIndexer (JSStringLiteral op)+ -- |+ -- Generate code in the simplified Javascript intermediate representation for an accessor based on+ -- a PureScript identifier. If the name is not valid in Javascript (symbol based, reserved name) an+ -- indexer is returned.+ --+ accessor :: Ident -> JS -> JS+ accessor (Ident prop) = accessorString prop+ accessor (Op op) = JSIndexer (JSStringLiteral op) -accessorString :: String -> JS -> JS-accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)- | otherwise = JSAccessor prop+ accessorString :: String -> JS -> JS+ accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)+ | otherwise = JSAccessor prop --- |--- Generate code in the simplified Javascript intermediate representation for a value or expression.----valueToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> Expr Ann -> SupplyT m JS-valueToJs m (Literal _ l) =- literalToValueJS m l-valueToJs m (Var (_, _, _, Just (IsConstructor _ [])) name) =- return $ JSAccessor "value" $ qualifiedToJS m id name-valueToJs m (Var (_, _, _, Just (IsConstructor _ _)) name) =- return $ JSAccessor "create" $ qualifiedToJS m id name-valueToJs m (Accessor _ prop val) =- accessorString prop <$> valueToJs m val-valueToJs m (ObjectUpdate _ o ps) = do- obj <- valueToJs m o- sts <- mapM (sndM $ valueToJs m) ps- extendObj obj sts-valueToJs _ e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =- let args = unAbs e- in return $ JSFunction Nothing (map identToJs args) (JSBlock $ map assign args)- where- unAbs :: Expr Ann -> [Ident]- unAbs (Abs _ arg val) = arg : unAbs val- unAbs _ = []- assign :: Ident -> JS- assign name = JSAssignment (accessorString (runIdent name) (JSVar "this"))- (var name)-valueToJs m (Abs _ arg val) = do- ret <- valueToJs m val- return $ JSFunction Nothing [identToJs arg] (JSBlock [JSReturn ret])-valueToJs m e@App{} = do- let (f, args) = unApp e []- args' <- mapM (valueToJs m) args- case f of- Var (_, _, _, Just IsNewtype) _ -> return (head args')- Var (_, _, _, Just (IsConstructor _ fields)) name | length args == length fields ->- return $ JSUnary JSNew $ JSApp (qualifiedToJS m id name) args'- Var (_, _, _, Just IsTypeClassConstructor) name ->- return $ JSUnary JSNew $ JSApp (qualifiedToJS m id name) args'- _ -> flip (foldl (\fn a -> JSApp fn [a])) args' <$> valueToJs m f- where- unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])- unApp (App _ val arg) args = unApp val (arg : args)- unApp other args = (other, args)-valueToJs m (Var _ ident) =- return $ varToJs m ident-valueToJs m (Case _ values binders) = do- vals <- mapM (valueToJs m) values- bindersToJs m binders vals-valueToJs m (Let _ ds val) = do- decls <- concat <$> mapM (bindToJs m) ds- ret <- valueToJs m val- return $ JSApp (JSFunction Nothing [] (JSBlock (decls ++ [JSReturn ret]))) []-valueToJs _ (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =- return $ JSVariableIntroduction ctor (Just $- JSObjectLiteral [("create",- JSFunction Nothing ["value"]- (JSBlock [JSReturn $ JSVar "value"]))])-valueToJs _ (Constructor _ _ (ProperName ctor) []) =- return $ iife ctor [ JSFunction (Just ctor) [] (JSBlock [])- , JSAssignment (JSAccessor "value" (JSVar ctor))- (JSUnary JSNew $ JSApp (JSVar ctor) []) ]-valueToJs _ (Constructor _ _ (ProperName ctor) fields) =- let constructor =- let body = [ JSAssignment (JSAccessor (identToJs f) (JSVar "this")) (var f) | f <- fields ]- in JSFunction (Just ctor) (identToJs `map` fields) (JSBlock body)- createFn =- let body = JSUnary JSNew $ JSApp (JSVar ctor) (var `map` fields)- in foldr (\f inner -> JSFunction Nothing [identToJs f] (JSBlock [JSReturn inner])) body fields- in return $ iife ctor [ constructor- , JSAssignment (JSAccessor "create" (JSVar ctor)) createFn- ]-iife :: String -> [JS] -> JS-iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a value or expression.+ --+ valueToJs :: Expr Ann -> m JS+ valueToJs (Literal _ l) =+ literalToValueJS l+ valueToJs (Var (_, _, _, Just (IsConstructor _ [])) name) =+ return $ JSAccessor "value" $ qualifiedToJS id name+ valueToJs (Var (_, _, _, Just (IsConstructor _ _)) name) =+ return $ JSAccessor "create" $ qualifiedToJS id name+ valueToJs (Accessor _ prop val) =+ accessorString prop <$> valueToJs val+ valueToJs (ObjectUpdate _ o ps) = do+ obj <- valueToJs o+ sts <- mapM (sndM valueToJs) ps+ extendObj obj sts+ valueToJs e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =+ let args = unAbs e+ in return $ JSFunction Nothing (map identToJs args) (JSBlock $ map assign args)+ where+ unAbs :: Expr Ann -> [Ident]+ unAbs (Abs _ arg val) = arg : unAbs val+ unAbs _ = []+ assign :: Ident -> JS+ assign name = JSAssignment (accessorString (runIdent name) (JSVar "this"))+ (var name)+ valueToJs (Abs _ arg val) = do+ ret <- valueToJs val+ return $ JSFunction Nothing [identToJs arg] (JSBlock [JSReturn ret])+ valueToJs e@App{} = do+ let (f, args) = unApp e []+ args' <- mapM valueToJs args+ case f of+ Var (_, _, _, Just IsNewtype) _ -> return (head args')+ Var (_, _, _, Just (IsConstructor _ fields)) name | length args == length fields ->+ return $ JSUnary JSNew $ JSApp (qualifiedToJS id name) args'+ Var (_, _, _, Just IsTypeClassConstructor) name ->+ return $ JSUnary JSNew $ JSApp (qualifiedToJS id name) args'+ _ -> flip (foldl (\fn a -> JSApp fn [a])) args' <$> valueToJs f+ where+ unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])+ unApp (App _ val arg) args = unApp val (arg : args)+ unApp other args = (other, args)+ valueToJs (Var _ ident) =+ return $ varToJs ident+ valueToJs (Case _ values binders) = do+ vals <- mapM valueToJs values+ bindersToJs binders vals+ valueToJs (Let _ ds val) = do+ ds' <- concat <$> mapM bindToJs ds+ ret <- valueToJs val+ return $ JSApp (JSFunction Nothing [] (JSBlock (ds' ++ [JSReturn ret]))) []+ valueToJs (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =+ return $ JSVariableIntroduction ctor (Just $+ JSObjectLiteral [("create",+ JSFunction Nothing ["value"]+ (JSBlock [JSReturn $ JSVar "value"]))])+ valueToJs (Constructor _ _ (ProperName ctor) []) =+ return $ iife ctor [ JSFunction (Just ctor) [] (JSBlock [])+ , JSAssignment (JSAccessor "value" (JSVar ctor))+ (JSUnary JSNew $ JSApp (JSVar ctor) []) ]+ valueToJs (Constructor _ _ (ProperName ctor) fields) =+ let constructor =+ let body = [ JSAssignment (JSAccessor (identToJs f) (JSVar "this")) (var f) | f <- fields ]+ in JSFunction (Just ctor) (identToJs `map` fields) (JSBlock body)+ createFn =+ let body = JSUnary JSNew $ JSApp (JSVar ctor) (var `map` fields)+ in foldr (\f inner -> JSFunction Nothing [identToJs f] (JSBlock [JSReturn inner])) body fields+ in return $ iife ctor [ constructor+ , JSAssignment (JSAccessor "create" (JSVar ctor)) createFn+ ] -literalToValueJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> Literal (Expr Ann) -> SupplyT m JS-literalToValueJS _ (NumericLiteral n) = return $ JSNumericLiteral n-literalToValueJS _ (StringLiteral s) = return $ JSStringLiteral s-literalToValueJS _ (BooleanLiteral b) = return $ JSBooleanLiteral b-literalToValueJS m (ArrayLiteral xs) = JSArrayLiteral <$> mapM (valueToJs m) xs-literalToValueJS m (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM (valueToJs m)) ps+ iife :: String -> [JS] -> JS+ iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) [] --- |--- Shallow copy an object.----extendObj :: (Functor m, Applicative m, Monad m) => JS -> [(String, JS)] -> SupplyT m JS-extendObj obj sts = do- newObj <- freshName- key <- freshName- let- jsKey = JSVar key- jsNewObj = JSVar newObj- block = JSBlock (objAssign:copy:extend ++ [JSReturn jsNewObj])- objAssign = JSVariableIntroduction newObj (Just $ JSObjectLiteral [])- copy = JSForIn key obj $ JSBlock [JSIfElse cond assign Nothing]- cond = JSApp (JSAccessor "hasOwnProperty" obj) [jsKey]- assign = JSBlock [JSAssignment (JSIndexer jsKey jsNewObj) (JSIndexer jsKey obj)]- stToAssign (s, js) = JSAssignment (JSAccessor s jsNewObj) js- extend = map stToAssign sts- return $ JSApp (JSFunction Nothing [] block) []+ literalToValueJS :: Literal (Expr Ann) -> m JS+ literalToValueJS (NumericLiteral n) = return $ JSNumericLiteral n+ literalToValueJS (StringLiteral s) = return $ JSStringLiteral s+ literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral b+ literalToValueJS (ArrayLiteral xs) = JSArrayLiteral <$> mapM valueToJs xs+ literalToValueJS (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM valueToJs) ps --- |--- Generate code in the simplified Javascript intermediate representation for a reference to a--- variable.----varToJs :: ModuleName -> Qualified Ident -> JS-varToJs _ (Qualified Nothing ident) = var ident-varToJs m qual = qualifiedToJS m id qual+ -- |+ -- Shallow copy an object.+ --+ extendObj :: JS -> [(String, JS)] -> m JS+ extendObj obj sts = do+ newObj <- freshName+ key <- freshName+ let+ jsKey = JSVar key+ jsNewObj = JSVar newObj+ block = JSBlock (objAssign:copy:extend ++ [JSReturn jsNewObj])+ objAssign = JSVariableIntroduction newObj (Just $ JSObjectLiteral [])+ copy = JSForIn key obj $ JSBlock [JSIfElse cond assign Nothing]+ cond = JSApp (JSAccessor "hasOwnProperty" obj) [jsKey]+ assign = JSBlock [JSAssignment (JSIndexer jsKey jsNewObj) (JSIndexer jsKey obj)]+ stToAssign (s, js) = JSAssignment (JSAccessor s jsNewObj) js+ extend = map stToAssign sts+ return $ JSApp (JSFunction Nothing [] block) [] --- |--- Generate code in the simplified Javascript intermediate representation for a reference to a--- variable that may have a qualified name.----qualifiedToJS :: ModuleName -> (a -> Ident) -> Qualified a -> JS-qualifiedToJS _ f (Qualified (Just (ModuleName [ProperName mn])) a) | mn == C.prim = JSVar . runIdent $ f a-qualifiedToJS m f (Qualified (Just m') a) | m /= m' = accessor (f a) (JSVar (moduleNameToJs m'))-qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a reference to a+ -- variable.+ --+ varToJs :: Qualified Ident -> JS+ varToJs (Qualified Nothing ident) = var ident+ varToJs qual = qualifiedToJS id qual --- |--- Generate code in the simplified Javascript intermediate representation for pattern match binders--- and guards.----bindersToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> [CaseAlternative Ann] -> [JS] -> SupplyT m JS-bindersToJs m binders vals = do- valNames <- replicateM (length vals) freshName- let assignments = zipWith JSVariableIntroduction valNames (map Just vals)- jss <- forM binders $ \(CaseAlternative bs result) -> do- ret <- guardsToJs result- go valNames ret bs- return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))- []- where- go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => [String] -> [JS] -> [Binder Ann] -> SupplyT m [JS]- go _ done [] = return done- go (v:vs) done' (b:bs) = do- done'' <- go vs done' bs- binderToJs m v done'' b- go _ _ _ = error "Invalid arguments to bindersToJs"+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a reference to a+ -- variable that may have a qualified name.+ --+ qualifiedToJS :: (a -> Ident) -> Qualified a -> JS+ qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar . runIdent $ f a+ qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar (moduleNameToJs mn'))+ qualifiedToJS f (Qualified _ a) = JSVar $ identToJs (f a) - guardsToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => Either [(Guard Ann, Expr Ann)] (Expr Ann) -> SupplyT m [JS]- guardsToJs (Left gs) = forM gs $ \(cond, val) -> do- cond' <- valueToJs m cond- done <- valueToJs m val- return $ JSIfElse cond' (JSBlock [JSReturn done]) Nothing- guardsToJs (Right v) = return . JSReturn <$> valueToJs m v+ -- |+ -- Generate code in the simplified Javascript intermediate representation for pattern match binders+ -- and guards.+ --+ bindersToJs :: [CaseAlternative Ann] -> [JS] -> m JS+ bindersToJs binders vals = do+ valNames <- replicateM (length vals) freshName+ let assignments = zipWith JSVariableIntroduction valNames (map Just vals)+ jss <- forM binders $ \(CaseAlternative bs result) -> do+ ret <- guardsToJs result+ go valNames ret bs+ return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ JSUnary JSNew $ JSApp (JSVar "Error") [JSStringLiteral "Failed pattern match"]])))+ []+ where+ go :: [String] -> [JS] -> [Binder Ann] -> m [JS]+ go _ done [] = return done+ go (v:vs) done' (b:bs) = do+ done'' <- go vs done' bs+ binderToJs v done'' b+ go _ _ _ = error "Invalid arguments to bindersToJs" --- |--- Generate code in the simplified Javascript intermediate representation for a pattern match--- binder.----binderToJs :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> String -> [JS] -> Binder Ann -> SupplyT m [JS]-binderToJs _ _ done (NullBinder{}) = return done-binderToJs m varName done (LiteralBinder _ l) =- literalToBinderJS m varName done l-binderToJs _ varName done (VarBinder _ ident) =- return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : done)-binderToJs m varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =- binderToJs m varName done b-binderToJs m varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ ctor bs) = do- js <- go (zip fields bs) done- return $ case ctorType of- ProductType -> js- SumType ->- [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS m (Ident . runProperName) ctor))- (JSBlock js)- Nothing]- where- go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => [(Ident, Binder Ann)] -> [JS] -> SupplyT m [JS]- go [] done' = return done'- go ((field, binder) : remain) done' = do- argVar <- freshName- done'' <- go remain done'- js <- binderToJs m argVar done'' binder- return (JSVariableIntroduction argVar (Just (JSAccessor (identToJs field) (JSVar varName))) : js)-binderToJs m varName done binder@(ConstructorBinder _ _ ctor _) | isCons ctor = do- let (headBinders, tailBinder) = uncons [] binder- numberOfHeadBinders = fromIntegral $ length headBinders- js1 <- foldM (\done' (headBinder, index) -> do- headVar <- freshName- jss <- binderToJs m headVar done' headBinder- return (JSVariableIntroduction headVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : jss)) done (zip headBinders [0..])- tailVar <- freshName- js2 <- binderToJs m tailVar js1 tailBinder- return [JSIfElse (JSBinary GreaterThanOrEqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left numberOfHeadBinders))) (JSBlock- ( JSVariableIntroduction tailVar (Just (JSApp (JSAccessor "slice" (JSVar varName)) [JSNumericLiteral (Left numberOfHeadBinders)])) :- js2- )) Nothing]- where- uncons :: [Binder Ann] -> Binder Ann -> ([Binder Ann], Binder Ann)- uncons acc (ConstructorBinder _ _ ctor' [h, t]) | isCons ctor' = uncons (h : acc) t- uncons acc tailBinder = (reverse acc, tailBinder)-binderToJs _ _ _ b@(ConstructorBinder{}) =- error $ "Invalid ConstructorBinder in binderToJs: " ++ show b-binderToJs m varName done (NamedBinder _ ident binder) = do- js <- binderToJs m varName done binder- return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)+ guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [JS]+ guardsToJs (Left gs) = forM gs $ \(cond, val) -> do+ cond' <- valueToJs cond+ done <- valueToJs val+ return $ JSIfElse cond' (JSBlock [JSReturn done]) Nothing+ guardsToJs (Right v) = return . JSReturn <$> valueToJs v -literalToBinderJS :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => ModuleName -> String -> [JS] -> Literal (Binder Ann) -> SupplyT m [JS]-literalToBinderJS _ varName done (NumericLiteral num) =- return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]-literalToBinderJS _ varName done (StringLiteral str) =- return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral str)) (JSBlock done) Nothing]-literalToBinderJS _ varName done (BooleanLiteral True) =- return [JSIfElse (JSVar varName) (JSBlock done) Nothing]-literalToBinderJS _ varName done (BooleanLiteral False) =- return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]-literalToBinderJS m varName done (ObjectLiteral bs) = go done bs- where- go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => [JS] -> [(String, Binder Ann)] -> SupplyT m [JS]- go done' [] = return done'- go done' ((prop, binder):bs') = do- propVar <- freshName- done'' <- go done' bs'- js <- binderToJs m propVar done'' binder- return (JSVariableIntroduction propVar (Just (accessorString prop (JSVar varName))) : js)-literalToBinderJS m varName done (ArrayLiteral bs) = do- js <- go done 0 bs- return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]- where- go :: (Functor m, Applicative m, Monad m, MonadReader (Options mode) m)- => [JS] -> Integer -> [Binder Ann] -> SupplyT m [JS]- go done' _ [] = return done'- go done' index (binder:bs') = do- elVar <- freshName- done'' <- go done' (index + 1) bs'- js <- binderToJs m elVar done'' binder- return (JSVariableIntroduction elVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : js)+ -- |+ -- Generate code in the simplified Javascript intermediate representation for a pattern match+ -- binder.+ --+ binderToJs :: String -> [JS] -> Binder Ann -> m [JS]+ binderToJs _ done (NullBinder{}) = return done+ binderToJs varName done (LiteralBinder _ l) =+ literalToBinderJS varName done l+ binderToJs varName done (VarBinder _ ident) =+ return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : done)+ binderToJs varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =+ binderToJs varName done b+ binderToJs varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ ctor bs) = do+ js <- go (zip fields bs) done+ return $ case ctorType of+ ProductType -> js+ SumType ->+ [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS (Ident . runProperName) ctor))+ (JSBlock js)+ Nothing]+ where+ go :: [(Ident, Binder Ann)] -> [JS] -> m [JS]+ go [] done' = return done'+ go ((field, binder) : remain) done' = do+ argVar <- freshName+ done'' <- go remain done'+ js <- binderToJs argVar done'' binder+ return (JSVariableIntroduction argVar (Just (JSAccessor (identToJs field) (JSVar varName))) : js)+ binderToJs varName done binder@(ConstructorBinder _ _ ctor _) | isCons ctor = do+ let (headBinders, tailBinder) = uncons [] binder+ numberOfHeadBinders = fromIntegral $ length headBinders+ js1 <- foldM (\done' (headBinder, index) -> do+ headVar <- freshName+ jss <- binderToJs headVar done' headBinder+ return (JSVariableIntroduction headVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : jss)) done (zip headBinders [0..])+ tailVar <- freshName+ js2 <- binderToJs tailVar js1 tailBinder+ return [JSIfElse (JSBinary GreaterThanOrEqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left numberOfHeadBinders))) (JSBlock+ ( JSVariableIntroduction tailVar (Just (JSApp (JSAccessor "slice" (JSVar varName)) [JSNumericLiteral (Left numberOfHeadBinders)])) :+ js2+ )) Nothing]+ where+ uncons :: [Binder Ann] -> Binder Ann -> ([Binder Ann], Binder Ann)+ uncons acc (ConstructorBinder _ _ ctor' [h, t]) | isCons ctor' = uncons (h : acc) t+ uncons acc tailBinder = (reverse acc, tailBinder)+ binderToJs _ _ b@(ConstructorBinder{}) =+ error $ "Invalid ConstructorBinder in binderToJs: " ++ show b+ binderToJs varName done (NamedBinder _ ident binder) = do+ js <- binderToJs varName done binder+ return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js) -isCons :: Qualified ProperName -> Bool-isCons (Qualified (Just mn) ctor) = mn == ModuleName [ProperName C.prim] && ctor == ProperName "Array"-isCons name = error $ "Unexpected argument in isCons: " ++ show name+ literalToBinderJS :: String -> [JS] -> Literal (Binder Ann) -> m [JS]+ literalToBinderJS varName done (NumericLiteral num) =+ return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]+ literalToBinderJS varName done (StringLiteral str) =+ return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral str)) (JSBlock done) Nothing]+ literalToBinderJS varName done (BooleanLiteral True) =+ return [JSIfElse (JSVar varName) (JSBlock done) Nothing]+ literalToBinderJS varName done (BooleanLiteral False) =+ return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]+ literalToBinderJS varName done (ObjectLiteral bs) = go done bs+ where+ go :: [JS] -> [(String, Binder Ann)] -> m [JS]+ go done' [] = return done'+ go done' ((prop, binder):bs') = do+ propVar <- freshName+ done'' <- go done' bs'+ js <- binderToJs propVar done'' binder+ return (JSVariableIntroduction propVar (Just (accessorString prop (JSVar varName))) : js)+ literalToBinderJS varName done (ArrayLiteral bs) = do+ js <- go done 0 bs+ return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]+ where+ go :: [JS] -> Integer -> [Binder Ann] -> m [JS]+ go done' _ [] = return done'+ go done' index (binder:bs') = do+ elVar <- freshName+ done'' <- go done' (index + 1) bs'+ js <- binderToJs elVar done'' binder+ return (JSVariableIntroduction elVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : js)++ isCons :: Qualified ProperName -> Bool+ isCons (Qualified (Just mn') ctor) = mn' == ModuleName [ProperName C.prim] && ctor == ProperName "Array"+ isCons name = error $ "Unexpected argument in isCons: " ++ show name
src/Language/PureScript/CoreFn/Desugar.hs view
@@ -40,14 +40,14 @@ -- Desugars a module from AST to CoreFn representation. -- moduleToCoreFn :: Environment -> A.Module -> Module Ann-moduleToCoreFn _ (A.Module _ _ Nothing) =+moduleToCoreFn _ (A.Module _ _ _ Nothing) = error "Module exports were not elaborated before moduleToCoreFn"-moduleToCoreFn env (A.Module mn decls (Just exps)) =+moduleToCoreFn env (A.Module coms mn decls (Just exps)) = let imports = nub $ mapMaybe importToCoreFn decls ++ findQualModules decls exps' = nub $ concatMap exportToCoreFn exps externs = nub $ mapMaybe externToCoreFn decls decls' = concatMap (declToCoreFn Nothing []) decls- in Module mn imports exps' externs decls'+ in Module coms mn imports exps' externs decls' where @@ -190,12 +190,17 @@ -- findQualModules :: [A.Declaration] -> [ModuleName] findQualModules decls =- let (f, _, _, _, _) = everythingOnValues (++) (const []) fqValues (const []) (const []) (const [])+ let (f, _, _, _, _) = everythingOnValues (++) (const []) fqValues fqBinders (const []) (const []) in f `concatMap` decls where fqValues :: A.Expr -> [ModuleName] fqValues (A.Var (Qualified (Just mn) _)) = [mn]+ fqValues (A.Constructor (Qualified (Just mn) _)) = [mn] fqValues _ = []+ + fqBinders :: A.Binder -> [ModuleName]+ fqBinders (A.ConstructorBinder (Qualified (Just mn) _) _) = [mn]+ fqBinders _ = [] -- | -- Desugars import declarations from AST to CoreFn representation.
src/Language/PureScript/CoreFn/Module.hs view
@@ -15,12 +15,14 @@ module Language.PureScript.CoreFn.Module where import Language.PureScript.CodeGen.JS.AST+import Language.PureScript.Comments import Language.PureScript.CoreFn.Expr import Language.PureScript.Names import Language.PureScript.Types data Module a = Module- { moduleName :: ModuleName+ { moduleComments :: [Comment]+ , moduleName :: ModuleName , moduleImports :: [ModuleName] , moduleExports :: [Ident] , moduleForeign :: [ForeignDecl]
src/Language/PureScript/DeadCodeElimination.hs view
@@ -29,7 +29,7 @@ eliminateDeadCode :: [ModuleName] -> [Module a] -> [Module a] eliminateDeadCode entryPoints ms = map go ms where- go (Module mn imps exps foreigns ds) = Module mn imps exps' foreigns' ds'+ go (Module coms mn imps exps foreigns ds) = Module coms mn imps exps' foreigns' ds' where ds' = filter (isUsed mn graph vertexFor entryPointVertices) ds foreigns' = filter (isUsed' mn graph vertexFor entryPointVertices . foreignIdent) foreigns@@ -61,7 +61,7 @@ -- Find dependencies for each member in a module. -- declarationsByModule :: Module a -> [(Key, [Key])]-declarationsByModule (Module mn _ _ fs ds) =+declarationsByModule (Module _ mn _ _ fs ds) = let fs' = map ((\name -> ((mn, name), [])) . foreignIdent) fs in fs' ++ concatMap go ds where
src/Language/PureScript/Errors.hs view
@@ -12,110 +12,488 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Language.PureScript.Errors where import Data.Either (lefts, rights)-import Data.String (IsString(..))-import Data.List (intersperse, intercalate)+import Data.List (intercalate) import Data.Monoid+import Data.Foldable (fold, foldMap) import Control.Monad.Except+import Control.Monad.Unify import Control.Applicative ((<$>)) import Language.PureScript.AST import Language.PureScript.Pretty import Language.PureScript.Types+import Language.PureScript.Names+import Language.PureScript.Kinds+import Language.PureScript.TypeClassDictionaries --- |--- Type for sources of type checking errors----data ErrorSource- -- |- -- An error which originated at a Expr- --- = ExprError Expr- -- |- -- An error which originated at a Type- --- | TypeError Type deriving (Show)+import qualified Text.PrettyPrint.Boxes as Box -- |--- Compilation errors+-- A type of error messages ---data CompileError- = CompileError- { -- |- -- Error message- --- compileErrorMessage :: String- -- |- -- The value where the error occurred- --- , compileErrorValue :: Maybe ErrorSource- -- |- -- Optional source position information- --- , compileErrorPosition :: Maybe SourceSpan- }+data ErrorMessage + = InfiniteType Type+ | InfiniteKind Kind+ | CannotReorderOperators+ | MultipleFixities Ident+ | OrphanTypeDeclaration Ident+ | OrphanFixityDeclaration String+ | RedefinedModule ModuleName+ | RedefinedIdent Ident+ | OverlappingNamesInLet+ | UnknownModule ModuleName+ | UnknownType (Qualified ProperName)+ | UnknownTypeClass (Qualified ProperName)+ | UnknownValue (Qualified Ident)+ | UnknownDataConstructor (Qualified ProperName) (Maybe (Qualified ProperName))+ | UnknownTypeConstructor (Qualified ProperName)+ | ConflictingImport String ModuleName+ | ConflictingImports String ModuleName ModuleName + | ConflictingTypeDecls ProperName+ | ConflictingCtorDecls ProperName+ | TypeConflictsWithClass ProperName+ | CtorConflictsWithClass ProperName+ | ClassConflictsWithType ProperName+ | ClassConflictsWithCtor ProperName+ | DuplicateClassExport ProperName+ | DuplicateValueExport Ident+ | DuplicateTypeArgument String+ | InvalidDoBind+ | InvalidDoLet+ | CycleInDeclaration Ident+ | CycleInTypeSynonym (Maybe ProperName)+ | NameIsUndefined Ident+ | NameNotInScope Ident+ | UndefinedTypeVariable ProperName+ | PartiallyAppliedSynonym (Qualified ProperName)+ | NotYetDefined [Ident] ErrorMessage+ | EscapedSkolem (Maybe Expr)+ | UnspecifiedSkolemScope+ | TypesDoNotUnify Type Type+ | KindsDoNotUnify Kind Kind+ | ConstrainedTypeUnified Type Type+ | OverlappingInstances (Qualified ProperName) [Type] [DictionaryValue]+ | NoInstanceFound (Qualified ProperName) [Type]+ | DuplicateLabel String (Maybe Expr)+ | DuplicateValueDeclaration Ident+ | ArgListLengthsDiffer Ident+ | OverlappingArgNames (Maybe Ident)+ | MissingClassMember Ident+ | ExpectedType Kind+ | IncorrectConstructorArity (Qualified ProperName)+ | SubsumptionCheckFailed+ | ExprDoesNotHaveType Expr Type+ | PropertyIsMissing String Type+ | ErrorUnifyingTypes Type Type ErrorMessage+ | CannotApplyFunction Type Expr+ | TypeSynonymInstance+ | InvalidNewtype+ | InvalidInstanceHead Type+ | TransitiveExportError DeclarationRef [DeclarationRef]+ | ErrorInExpression Expr ErrorMessage+ | ErrorInModule ModuleName ErrorMessage+ | ErrorInInstance (Qualified ProperName) [Type] ErrorMessage+ | ErrorInSubsumption Type Type ErrorMessage+ | ErrorCheckingType Expr Type ErrorMessage+ | ErrorCheckingKind Type ErrorMessage+ | ErrorInferringType Expr ErrorMessage+ | ErrorInApplication Expr Type Expr ErrorMessage+ | ErrorInDataConstructor ProperName ErrorMessage+ | ErrorInTypeConstructor ProperName ErrorMessage+ | ErrorInBindingGroup [Ident] ErrorMessage+ | ErrorInDataBindingGroup ErrorMessage+ | ErrorInTypeSynonym ProperName ErrorMessage+ | ErrorInValueDeclaration Ident ErrorMessage+ | ErrorInForeignImport Ident ErrorMessage+ | PositionedError SourceSpan ErrorMessage deriving (Show)+ +instance UnificationError Type ErrorMessage where+ occursCheckFailed = InfiniteType+ +instance UnificationError Kind ErrorMessage where+ occursCheckFailed = InfiniteKind -- |+-- Get the error code for a particular error type+--+errorCode :: ErrorMessage -> String+errorCode (InfiniteType _) = "InfiniteType"+errorCode (InfiniteKind _) = "InfiniteKind"+errorCode CannotReorderOperators = "CannotReorderOperators"+errorCode (MultipleFixities _) = "MultipleFixities"+errorCode (OrphanTypeDeclaration _) = "OrphanTypeDeclaration"+errorCode (OrphanFixityDeclaration _) = "OrphanFixityDeclaration"+errorCode (RedefinedModule _) = "RedefinedModule"+errorCode (RedefinedIdent _) = "RedefinedIdent"+errorCode OverlappingNamesInLet = "OverlappingNamesInLet"+errorCode (UnknownModule _) = "UnknownModule"+errorCode (UnknownType _) = "UnknownType"+errorCode (UnknownTypeClass _) = "UnknownTypeClass"+errorCode (UnknownValue _) = "UnknownValue"+errorCode (UnknownDataConstructor _ _) = "UnknownDataConstructor"+errorCode (UnknownTypeConstructor _) = "UnknownTypeConstructor"+errorCode (ConflictingImport _ _) = "ConflictingImport"+errorCode (ConflictingImports _ _ _) = "ConflictingImports"+errorCode (ConflictingTypeDecls _) = "ConflictingTypeDecls"+errorCode (ConflictingCtorDecls _) = "ConflictingCtorDecls"+errorCode (TypeConflictsWithClass _) = "TypeConflictsWithClass"+errorCode (CtorConflictsWithClass _) = "CtorConflictsWithClass"+errorCode (ClassConflictsWithType _) = "ClassConflictsWithType"+errorCode (ClassConflictsWithCtor _) = "ClassConflictsWithCtor"+errorCode (DuplicateClassExport _) = "DuplicateClassExport"+errorCode (DuplicateValueExport _) = "DuplicateValueExport"+errorCode (DuplicateTypeArgument _) = "DuplicateTypeArgument"+errorCode InvalidDoBind = "InvalidDoBind"+errorCode InvalidDoLet = "InvalidDoLet"+errorCode (CycleInDeclaration _) = "CycleInDeclaration"+errorCode (CycleInTypeSynonym _) = "CycleInTypeSynonym"+errorCode (NameIsUndefined _) = "NameIsUndefined"+errorCode (NameNotInScope _) = "NameNotInScope"+errorCode (UndefinedTypeVariable _) = "UndefinedTypeVariable"+errorCode (PartiallyAppliedSynonym _) = "PartiallyAppliedSynonym"+errorCode (EscapedSkolem _) = "EscapedSkolem"+errorCode UnspecifiedSkolemScope = "UnspecifiedSkolemScope"+errorCode (TypesDoNotUnify _ _) = "TypesDoNotUnify"+errorCode (KindsDoNotUnify _ _) = "KindsDoNotUnify"+errorCode (ConstrainedTypeUnified _ _) = "ConstrainedTypeUnified"+errorCode (OverlappingInstances _ _ _) = "OverlappingInstances"+errorCode (NoInstanceFound _ _) = "NoInstanceFound"+errorCode (DuplicateLabel _ _) = "DuplicateLabel"+errorCode (DuplicateValueDeclaration _) = "DuplicateValueDeclaration"+errorCode (ArgListLengthsDiffer _) = "ArgListLengthsDiffer"+errorCode (OverlappingArgNames _) = "OverlappingArgNames"+errorCode (MissingClassMember _) = "MissingClassMember"+errorCode (ExpectedType _) = "ExpectedType"+errorCode (IncorrectConstructorArity _) = "IncorrectConstructorArity"+errorCode SubsumptionCheckFailed = "SubsumptionCheckFailed"+errorCode (ExprDoesNotHaveType _ _) = "ExprDoesNotHaveType"+errorCode (PropertyIsMissing _ _) = "PropertyIsMissing"+errorCode (ErrorUnifyingTypes _ _ _) = "ErrorUnifyingTypes"+errorCode (CannotApplyFunction _ _) = "CannotApplyFunction"+errorCode TypeSynonymInstance = "TypeSynonymInstance"+errorCode InvalidNewtype = "InvalidNewtype"+errorCode (InvalidInstanceHead _) = "InvalidInstanceHead"+errorCode (TransitiveExportError _ _) = "TransitiveExportError"+errorCode (NotYetDefined _ e) = errorCode e+errorCode (ErrorInExpression _ e) = errorCode e+errorCode (ErrorInModule _ e) = errorCode e+errorCode (ErrorInInstance _ _ e) = errorCode e+errorCode (ErrorInSubsumption _ _ e) = errorCode e+errorCode (ErrorCheckingType _ _ e) = errorCode e+errorCode (ErrorCheckingKind _ e) = errorCode e+errorCode (ErrorInferringType _ e) = errorCode e+errorCode (ErrorInApplication _ _ _ e) = errorCode e+errorCode (ErrorInDataConstructor _ e) = errorCode e+errorCode (ErrorInTypeConstructor _ e) = errorCode e+errorCode (ErrorInBindingGroup _ e) = errorCode e+errorCode (ErrorInDataBindingGroup e) = errorCode e+errorCode (ErrorInTypeSynonym _ e) = errorCode e+errorCode (ErrorInValueDeclaration _ e) = errorCode e+errorCode (ErrorInForeignImport _ e) = errorCode e+errorCode (PositionedError _ e) = errorCode e+ +-- | -- A stack trace for an error ---data ErrorStack- = ErrorStack { runErrorStack :: [CompileError] }- | MultipleErrors [ErrorStack] deriving (Show)+newtype MultipleErrors = MultipleErrors + { runMultipleErrors :: [ErrorMessage] } deriving (Show, Monoid)+ +instance UnificationError Type MultipleErrors where+ occursCheckFailed = errorMessage . occursCheckFailed+ +instance UnificationError Kind MultipleErrors where+ occursCheckFailed = errorMessage . occursCheckFailed --- TODO: Remove strMsg, the IsString instance, and unnecessary--- OverloadedStrings pragmas. See #745--- | Create an ErrorStack from a string-strMsg :: String -> ErrorStack-strMsg s = ErrorStack [CompileError s Nothing Nothing]+-- |+-- Create an error set from a single error message+--+errorMessage :: ErrorMessage -> MultipleErrors+errorMessage err = MultipleErrors [err] -instance IsString ErrorStack where- fromString = strMsg+-- |+-- Lift a function on ErrorMessage to a function on MultipleErrors+--+onErrorMessages :: (ErrorMessage -> ErrorMessage) -> MultipleErrors -> MultipleErrors+onErrorMessages f = MultipleErrors . map f . runMultipleErrors -prettyPrintErrorStack :: Bool -> ErrorStack -> String-prettyPrintErrorStack printFullStack (ErrorStack es) =- case mconcat $ map (Last . compileErrorPosition) es of- Last (Just sourcePos) -> "Error at " ++ show sourcePos ++ ": \n" ++ prettyPrintErrorStack'- _ -> prettyPrintErrorStack'+-- |+-- Pretty print a single error, simplifying if necessary+--+prettyPrintSingleError :: Bool -> ErrorMessage -> Box.Box+prettyPrintSingleError full e = prettyPrintErrorMessage (if full then e else simplifyErrorMessage e) where- prettyPrintErrorStack' :: String- prettyPrintErrorStack'- | printFullStack = intercalate "\n" (map showError (filter isErrorNonEmpty es))- | otherwise =- let- es' = filter isErrorNonEmpty es- in case length es' of- 1 -> showError (head es')- _ -> showError (head es') ++ "\n" ++ showError (last es')-prettyPrintErrorStack printFullStack (MultipleErrors es) =- unlines $ intersperse "" $ "Multiple errors:" : map (prettyPrintErrorStack printFullStack) es+ -- |+ -- Pretty print an ErrorMessage+ --+ prettyPrintErrorMessage :: ErrorMessage -> Box.Box+ prettyPrintErrorMessage em =+ paras+ [ go em+ , line ("See " ++ wikiUri ++ " for more information, or to contribute content related to this error.") + ]+ where+ wikiUri :: String+ wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e+ + go :: ErrorMessage -> Box.Box+ go InvalidDoBind = line "Bind statement cannot be the last statement in a do block"+ go InvalidDoLet = line "Let statement cannot be the last statement in a do block"+ go CannotReorderOperators = line "Unable to reorder operators"+ go UnspecifiedSkolemScope = line "Skolem variable scope is unspecified"+ go OverlappingNamesInLet = line "Overlapping names in let binding."+ go (InfiniteType ty) = paras [ line "Infinite type detected: "+ , indent $ line $ prettyPrintType ty+ ]+ go (InfiniteKind ki) = paras [ line "Infinite kind detected: "+ , indent $ line $ prettyPrintKind ki+ ]+ go (MultipleFixities name) = line $ "Multiple fixity declarations for " ++ show name+ go (OrphanTypeDeclaration nm) = line $ "Orphan type declaration for " ++ show nm+ go (OrphanFixityDeclaration op) = line $ "Orphan fixity declaration for " ++ show op+ go (RedefinedModule name) = line $ "Module " ++ show name ++ " has been defined multiple times"+ go (RedefinedIdent name) = line $ "Name " ++ show name ++ " has been defined multiple times"+ go (UnknownModule mn) = line $ "Unknown module " ++ show mn+ go (UnknownType name) = line $ "Unknown type " ++ show name+ go (UnknownTypeClass name) = line $ "Unknown type class " ++ show name+ go (UnknownValue name) = line $ "Unknown value " ++ show name+ go (UnknownTypeConstructor name) = line $ "Unknown type constructor " ++ show name+ go (UnknownDataConstructor dc tc) = line $ "Unknown data constructor " ++ show dc ++ foldMap ((" for type constructor " ++) . show) tc+ go (ConflictingImport nm mn) = line $ "Declaration " ++ nm ++ " conflicts with import " ++ show mn + go (ConflictingImports nm m1 m2) = line $ "Conflicting imports for " ++ nm ++ " from modules " ++ show m1 ++ " and " ++ show m2+ go (ConflictingTypeDecls nm) = line $ "Conflicting type declarations for " ++ show nm+ go (ConflictingCtorDecls nm) = line $ "Conflicting data constructor declarations for " ++ show nm+ go (TypeConflictsWithClass nm) = line $ "Type " ++ show nm ++ " conflicts with type class declaration of the same name"+ go (CtorConflictsWithClass nm) = line $ "Data constructor " ++ show nm ++ " conflicts with type class declaration of the same name"+ go (ClassConflictsWithType nm) = line $ "Type class " ++ show nm ++ " conflicts with type declaration of the same name"+ go (ClassConflictsWithCtor nm) = line $ "Type class " ++ show nm ++ " conflicts with data constructor declaration of the same name"+ go (DuplicateClassExport nm) = line $ "Duplicate export declaration for type class " ++ show nm+ go (DuplicateValueExport nm) = line $ "Duplicate export declaration for value " ++ show nm+ go (CycleInDeclaration nm) = line $ "Cycle in declaration of " ++ show nm+ go (NotYetDefined names err) = paras [ line $ "The following are not yet defined here: " ++ intercalate ", " (map show names) ++ ":"+ , indent $ go err+ ]+ go (CycleInTypeSynonym pn) = line $ "Cycle in type synonym" ++ foldMap ((" " ++) . show) pn+ go (NameIsUndefined ident) = line $ show ident ++ " is undefined"+ go (NameNotInScope ident) = line $ show ident ++ " may not be defined in the current scope"+ go (UndefinedTypeVariable name) = line $ "Type variable " ++ show name ++ " is undefined"+ go (PartiallyAppliedSynonym name) = line $ "Partially applied type synonym " ++ show name+ go (EscapedSkolem binding) = paras $ [ line "Rigid/skolem type variable has escaped." ]+ <> foldMap (\expr -> [ line "Relevant expression: "+ , indent $ line $ prettyPrintValue expr + ]) binding+ go (TypesDoNotUnify t1 t2) = paras [ line "Cannot unify type"+ , indent $ line $ prettyPrintType t1+ , line "with type"+ , indent $ line $ prettyPrintType t2+ ]+ go (KindsDoNotUnify k1 k2) = paras [ line "Cannot unify kind"+ , indent $ line $ prettyPrintKind k1+ , line "with kind"+ , indent $ line $ prettyPrintKind k2+ ]+ go (ConstrainedTypeUnified t1 t2) = paras [ line "Cannot unify constrained type"+ , indent $ line $ prettyPrintType t1+ , line "with type"+ , indent $ line $ prettyPrintType t2+ ]+ go (OverlappingInstances nm ts ds) = paras [ line $ "Overlapping instances found for " ++ show nm ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"+ , paras $ map prettyPrintDictionaryValue ds+ ]+ go (NoInstanceFound nm ts) = line $ "No instance found for " ++ show nm ++ " " ++ unwords (map prettyPrintTypeAtom ts)+ go (DuplicateLabel l expr) = paras $ [ line $ "Duplicate label " ++ show l ++ " in row." ]+ <> foldMap (\expr' -> [ line "Relevant expression: "+ , indent $ line $ prettyPrintValue expr' + ]) expr+ go (DuplicateTypeArgument name) = line $ "Duplicate type argument " ++ show name+ go (DuplicateValueDeclaration nm) = line $ "Duplicate value declaration for " ++ show nm+ go (ArgListLengthsDiffer ident) = line $ "Argument list lengths differ in declaration " ++ show ident+ go (OverlappingArgNames ident) = line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration" ++) . show) ident+ go (MissingClassMember ident) = line $ "Member " ++ show ident ++ " has not been implemented"+ go (ExpectedType kind) = line $ "Expected type of kind *, was " ++ prettyPrintKind kind+ go (IncorrectConstructorArity nm) = line $ "Wrong number of arguments to constructor " ++ show nm+ go SubsumptionCheckFailed = line $ "Unable to check type subsumption"+ go (ExprDoesNotHaveType expr ty) = paras [ line "Expression"+ , indent $ line $ prettyPrintValue expr+ , line "does not have type"+ , indent $ line $ prettyPrintType ty+ ]+ go (PropertyIsMissing prop row) = line $ "Row " ++ prettyPrintRow row ++ " lacks required property " ++ show prop+ go (CannotApplyFunction fn arg) = paras [ line "Cannot apply function of type"+ , indent $ line $ prettyPrintType fn+ , line "to argument"+ , indent $ line $ prettyPrintValue arg+ ]+ go TypeSynonymInstance = line "Type synonym instances are disallowed"+ go InvalidNewtype = line "Newtypes must define a single constructor with a single argument"+ go (InvalidInstanceHead ty) = paras [ line "Invalid type in class instance head:"+ , indent $ line $ prettyPrintType ty+ ]+ go (TransitiveExportError x ys) = paras $ (line $ "An export for " ++ prettyPrintExport x ++ " requires the following to also be exported: ")+ : map (line . prettyPrintExport) ys+ go (ErrorUnifyingTypes t1 t2 err) = paras [ line "Error unifying type "+ , indent $ line $ prettyPrintType t1+ , line "with type"+ , indent $ line $ prettyPrintType t2+ , go err+ ]+ go (ErrorInExpression expr err) = paras [ line "Error in expression:"+ , indent $ line $ prettyPrintValue expr+ , go err+ ]+ go (ErrorInModule mn err) = paras [ line $ "Error in module " ++ show mn ++ ":"+ , go err+ ]+ go (ErrorInSubsumption t1 t2 err) = paras [ line "Error checking that type "+ , indent $ line $ prettyPrintType t1+ , line "subsumes type"+ , indent $ line $ prettyPrintType t2+ , go err+ ]+ go (ErrorInInstance name ts err) = paras [ line $ "Error in type class instance " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"+ , go err+ ]+ go (ErrorCheckingKind ty err) = paras [ line "Error checking kind of type "+ , indent $ line $ prettyPrintType ty+ , go err+ ]+ go (ErrorInferringType expr err) = paras [ line "Error inferring type of value "+ , indent $ line $ prettyPrintValue expr+ , go err+ ]+ go (ErrorCheckingType expr ty err) = paras [ line "Error checking that value "+ , indent $ line $ prettyPrintValue expr+ , line "has type"+ , indent $ line $ prettyPrintType ty+ , go err+ ]+ go (ErrorInApplication f t a err) = paras [ line "Error applying function"+ , indent $ line $ prettyPrintValue f+ , line "of type"+ , indent $ line $ prettyPrintType t+ , line "to argument"+ , indent $ line $ prettyPrintValue a+ , go err+ ]+ go (ErrorInDataConstructor nm err) = paras [ line $ "Error in data constructor " ++ show nm ++ ":"+ , go err+ ]+ go (ErrorInTypeConstructor nm err) = paras [ line $ "Error in type constructor " ++ show nm ++ ":"+ , go err+ ]+ go (ErrorInBindingGroup nms err) = paras [ line $ "Error in binding group " ++ intercalate ", " (map show nms) ++ ":"+ , go err+ ]+ go (ErrorInDataBindingGroup err) = paras [ line $ "Error in data binding group:"+ , go err+ ]+ go (ErrorInTypeSynonym name err) = paras [ line $ "Error in type synonym " ++ show name ++ ":"+ , go err+ ]+ go (ErrorInValueDeclaration n err) = paras [ line $ "Error in value declaration " ++ show n ++ ":"+ , go err+ ]+ go (ErrorInForeignImport nm err) = paras [ line $ "Error in foreign import " ++ show nm ++ ":"+ , go err+ ]+ go (PositionedError pos err) = paras [ line $ "Error at " ++ show pos ++ ":"+ , indent $ go err+ ] -stringifyErrorStack :: (MonadError String m) => Bool -> Either ErrorStack a -> m a-stringifyErrorStack printFullStack = either (throwError . prettyPrintErrorStack printFullStack) return+ line :: String -> Box.Box+ line = Box.text -isErrorNonEmpty :: CompileError -> Bool-isErrorNonEmpty = not . null . compileErrorMessage+ paras :: [Box.Box] -> Box.Box+ paras = Box.vcat Box.left -showError :: CompileError -> String-showError (CompileError msg Nothing _) = msg-showError (CompileError msg (Just (ExprError val)) _) = "Error in expression " ++ prettyPrintValue val ++ ":\n" ++ msg-showError (CompileError msg (Just (TypeError ty)) _) = "Error in type " ++ prettyPrintType ty ++ ":\n" ++ msg+ indent :: Box.Box -> Box.Box+ indent = Box.moveRight 2 -mkErrorStack :: String -> Maybe ErrorSource -> ErrorStack-mkErrorStack msg t = ErrorStack [mkCompileError msg t]+ -- |+ -- Render a DictionaryValue fit for human consumption in error messages+ --+ prettyPrintDictionaryValue :: DictionaryValue -> Box.Box+ prettyPrintDictionaryValue (LocalDictionaryValue _) = line "Dictionary in scope"+ prettyPrintDictionaryValue (GlobalDictionaryValue nm) = line (show nm)+ prettyPrintDictionaryValue (DependentDictionaryValue nm args) = paras [ line $ (show nm) ++ " via"+ , indent $ paras $ map prettyPrintDictionaryValue args+ ]+ prettyPrintDictionaryValue (SubclassDictionaryValue sup nm _) = paras [ line $ (show nm) ++ " via superclass"+ , indent $ prettyPrintDictionaryValue sup+ ]+ + -- |+ -- Pretty print and export declaration+ -- + prettyPrintExport :: DeclarationRef -> String+ prettyPrintExport (TypeRef pn _) = show pn+ prettyPrintExport (ValueRef ident) = show ident+ prettyPrintExport (TypeClassRef pn) = show pn+ prettyPrintExport (TypeInstanceRef ident) = show ident+ prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref -mkCompileError :: String -> Maybe ErrorSource -> CompileError-mkCompileError msg t = CompileError msg t Nothing+ -- |+ -- Simplify an error message+ --+ simplifyErrorMessage :: ErrorMessage -> ErrorMessage+ simplifyErrorMessage = unwrap Nothing+ where+ unwrap :: Maybe SourceSpan -> ErrorMessage -> ErrorMessage+ unwrap pos (ErrorInExpression _ err) = unwrap pos err+ unwrap pos (ErrorInInstance name ts err) = ErrorInInstance name ts (unwrap pos err)+ unwrap pos (ErrorInSubsumption t1 t2 err) = ErrorInSubsumption t1 t2 (unwrap pos err)+ unwrap pos (ErrorUnifyingTypes _ _ err) = unwrap pos err+ unwrap pos (ErrorInferringType _ err) = unwrap pos err+ unwrap pos (ErrorCheckingType _ _ err) = unwrap pos err+ unwrap pos (ErrorCheckingKind ty err) = ErrorCheckingKind ty (unwrap pos err)+ unwrap pos (ErrorInModule mn err) = ErrorInModule mn (unwrap pos err)+ unwrap pos (ErrorInApplication _ _ _ err) = unwrap pos err+ unwrap pos (ErrorInDataConstructor nm err) = ErrorInDataConstructor nm (unwrap pos err)+ unwrap pos (ErrorInTypeConstructor nm err) = ErrorInTypeConstructor nm (unwrap pos err)+ unwrap pos (ErrorInBindingGroup nms err) = ErrorInBindingGroup nms (unwrap pos err)+ unwrap pos (ErrorInDataBindingGroup err) = ErrorInDataBindingGroup (unwrap pos err)+ unwrap pos (ErrorInTypeSynonym nm err) = ErrorInTypeSynonym nm (unwrap pos err)+ unwrap pos (ErrorInValueDeclaration nm err) = ErrorInValueDeclaration nm (unwrap pos err)+ unwrap pos (ErrorInForeignImport nm err) = ErrorInForeignImport nm (unwrap pos err)+ unwrap pos (NotYetDefined ns err) = NotYetDefined ns (unwrap pos err)+ unwrap _ (PositionedError pos err) = unwrap (Just pos) err+ unwrap pos other = wrap pos other+ + wrap :: Maybe SourceSpan -> ErrorMessage -> ErrorMessage+ wrap Nothing = id+ wrap (Just pos) = PositionedError pos -positionError :: SourceSpan -> CompileError-positionError pos = CompileError "" Nothing (Just pos)+-- |+-- Pretty print multiple errors+--+prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String+prettyPrintMultipleErrors full (MultipleErrors [e]) = renderBox $+ prettyPrintSingleError full e +prettyPrintMultipleErrors full (MultipleErrors es) = renderBox $+ Box.vcat Box.left [ Box.text "Multiple errors:"+ , Box.vsep 1 Box.left $ map (Box.moveRight 2 . prettyPrintSingleError full) es+ ] +renderBox :: Box.Box -> String+renderBox = unlines . map trimEnd . lines . Box.render+ where+ trimEnd = reverse . dropWhile (== ' ') . reverse+ -- |+-- Interpret multiple errors in a monad supporting errors+--+interpretMultipleErrors :: (MonadError String m) => Bool -> Either MultipleErrors a -> m a+interpretMultipleErrors printFullStack = either (throwError . prettyPrintMultipleErrors printFullStack) return++-- | -- Rethrow an error with a more detailed error message in the case of failure -- rethrow :: (MonadError e m) => (e -> e) -> m a -> m a@@ -124,30 +502,23 @@ -- | -- Rethrow an error with source position information ---rethrowWithPosition :: (MonadError ErrorStack m) => SourceSpan -> m a -> m a-rethrowWithPosition pos = rethrow (positionError pos `combineErrors`)+rethrowWithPosition :: (MonadError MultipleErrors m) => SourceSpan -> m a -> m a+rethrowWithPosition pos = rethrow (onErrorMessages withPosition)+ where+ withPosition :: ErrorMessage -> ErrorMessage+ withPosition (PositionedError _ err) = withPosition err+ withPosition err = PositionedError pos err -- | -- Collect errors in in parallel ---parU :: (MonadError ErrorStack m, Functor m) => [a] -> (a -> m b) -> m [b]+parU :: (MonadError MultipleErrors m, Functor m) => [a] -> (a -> m b) -> m [b] parU xs f = forM xs (withError . f) >>= collectErrors where- withError :: (MonadError ErrorStack m, Functor m) => m a -> m (Either ErrorStack a)+ withError :: (MonadError MultipleErrors m, Functor m) => m a -> m (Either MultipleErrors a) withError u = catchError (Right <$> u) (return . Left) - collectErrors :: (MonadError ErrorStack m, Functor m) => [Either ErrorStack a] -> m [a]+ collectErrors :: (MonadError MultipleErrors m, Functor m) => [Either MultipleErrors a] -> m [a] collectErrors es = case lefts es of- [err] -> throwError err [] -> return $ rights es- errs -> throwError $ MultipleErrors errs- --- |--- Add an extra error string onto the top of each error stack in a list of possibly many errors----combineErrors :: CompileError -> ErrorStack -> ErrorStack-combineErrors ce err = go (ErrorStack [ce]) err- where - go (ErrorStack xs) (ErrorStack ys) = ErrorStack (xs ++ ys)- go (MultipleErrors es) x = MultipleErrors [ go e x | e <- es ]- go x (MultipleErrors es) = MultipleErrors [ go x e | e <- es ]+ errs -> throwError $ fold errs
src/Language/PureScript/ModuleDependencies.hs view
@@ -41,7 +41,7 @@ -- sortModules :: (MonadError String m) => [Module] -> m ([Module], ModuleGraph) sortModules ms = do- let verts = map (\m@(Module _ ds _) -> (m, getModuleName m, nub (concatMap usedModules ds))) ms+ let verts = map (\m@(Module _ _ ds _) -> (m, getModuleName m, nub (concatMap usedModules ds))) ms ms' <- mapM toModule $ stronglyConnComp verts let moduleGraph = map (\(_, mn, deps) -> (mn, deps)) verts return (ms', moduleGraph)
src/Language/PureScript/Parser/Declarations.hs view
@@ -24,6 +24,8 @@ parseGuard, parseBinder, parseBinderNoParens,+ parseImportDeclaration',+ parseLocalDeclaration ) where import Prelude hiding (lex)@@ -146,6 +148,11 @@ parseImportDeclaration :: TokenParser Declaration parseImportDeclaration = do+ (mn, declType, asQ) <- parseImportDeclaration'+ return $ ImportDeclaration mn declType asQ++parseImportDeclaration' :: TokenParser (ModuleName, ImportDeclarationType, (Maybe ModuleName))+parseImportDeclaration' = do reserved "import" indented qualImport <|> stdImport@@ -157,21 +164,21 @@ stdImportHiding mn = do reserved "hiding" declType <- importDeclarationType Hiding- return $ ImportDeclaration mn declType Nothing+ return (mn, declType, Nothing) stdImportQualifying mn = do- declType <- importDeclarationType Qualifying- return $ ImportDeclaration mn declType Nothing+ declType <- importDeclarationType Explicit+ return (mn, declType, Nothing) qualImport = do reserved "qualified" indented moduleName' <- moduleName- declType <- importDeclarationType Qualifying+ declType <- importDeclarationType Explicit reserved "as" asQ <- moduleName- return $ ImportDeclaration moduleName' declType (Just asQ)+ return (moduleName', declType, Just asQ) importDeclarationType expectedType = do idents <- P.optionMaybe $ indented *> (parens $ commaSep parseDeclarationRef)- return $ fromMaybe Unqualified (expectedType <$> idents)+ return $ fromMaybe Implicit (expectedType <$> idents) parseDeclarationRef :: TokenParser DeclarationRef@@ -242,13 +249,14 @@ -- parseModule :: TokenParser Module parseModule = do+ comments <- C.readComments reserved "module" indented name <- moduleName exports <- P.optionMaybe $ parens $ commaSep1 parseDeclarationRef reserved "where" decls <- mark (P.many (same *> parseDeclaration))- return $ Module name decls exports+ return $ Module comments name decls exports -- | -- Parse a collection of modules
src/Language/PureScript/Pretty/JS.hs view
@@ -272,26 +272,26 @@ ++ fromMaybe "" name ++ "(" ++ intercalate ", " args ++ ") " ++ ret ]- , [ binary LessThan "<" ]- , [ binary LessThanOrEqualTo "<=" ]- , [ binary GreaterThan ">" ]- , [ binary GreaterThanOrEqualTo ">=" ] , [ Wrap typeOf $ \_ s -> "typeof " ++ s ]- , [ AssocR instanceOf $ \v1 v2 -> v1 ++ " instanceof " ++ v2 ]- , [ unary Not "!" ]- , [ unary BitwiseNot "~" ]- , [ negateOperator ]- , [ unary Positive "+" ]+ , [ unary Not "!"+ , unary BitwiseNot "~"+ , unary Positive "+"+ , negateOperator ] , [ binary Multiply "*" , binary Divide "/" , binary Modulus "%" ] , [ binary Add "+" , binary Subtract "-" ]- , [ binary ShiftLeft "<<" ]- , [ binary ShiftRight ">>" ]- , [ binary ZeroFillShiftRight ">>>" ]- , [ binary EqualTo "===" ]- , [ binary NotEqualTo "!==" ]+ , [ binary ShiftLeft "<<"+ , binary ShiftRight ">>"+ , binary ZeroFillShiftRight ">>>" ]+ , [ binary LessThan "<"+ , binary LessThanOrEqualTo "<="+ , binary GreaterThan ">"+ , binary GreaterThanOrEqualTo ">="+ , AssocR instanceOf $ \v1 v2 -> v1 ++ " instanceof " ++ v2 ]+ , [ binary EqualTo "==="+ , binary NotEqualTo "!==" ] , [ binary BitwiseAnd "&" ] , [ binary BitwiseXor "^" ] , [ binary BitwiseOr "|" ]
src/Language/PureScript/Pretty/Values.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- -- Module : Language.PureScript.Pretty.Values--- Copyright : Kinds.hs(c) Phil Freeman 2013+-- Copyright : (c) Phil Freeman 2013 -- License : MIT -- -- Maintainer : Phil Freeman <paf31@cantab.net>@@ -29,7 +29,7 @@ import Language.PureScript.AST import Language.PureScript.Names import Language.PureScript.Pretty.Common-import Language.PureScript.Pretty.Types (prettyPrintType)+import Language.PureScript.Pretty.Types (prettyPrintType, prettyPrintTypeAtom) literals :: Pattern PrinterState Expr String literals = mkPattern' match@@ -76,7 +76,7 @@ ] match (OperatorSection op (Right val)) = return $ "(" ++ prettyPrintValue op ++ " " ++ prettyPrintValue val ++ ")" match (OperatorSection op (Left val)) = return $ "(" ++ prettyPrintValue val ++ " " ++ prettyPrintValue op ++ ")"- match (TypeClassDictionary name _ _) = return $ "<<dict " ++ show name ++ ">>"+ match (TypeClassDictionary _ (name, tys) _) = return $ "<<dict " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom tys) ++ ">>" match (SuperClassDictionary name _) = return $ "<<superclass dict " ++ show name ++ ">>" match (TypedValue _ val _) = prettyPrintValue' val match (PositionedValue _ _ val) = prettyPrintValue' val
src/Language/PureScript/Renamer.hs view
@@ -113,7 +113,7 @@ renameInModules = map go where go :: Module Ann -> Module Ann- go m@(Module _ _ _ _ decls) = m { moduleDecls = renameInDecl' (findDeclIdents decls) `map` decls }+ go m@(Module _ _ _ _ _ decls) = m { moduleDecls = renameInDecl' (findDeclIdents decls) `map` decls } renameInDecl' :: [Ident] -> Bind Ann -> Bind Ann renameInDecl' scope = runRename scope . renameInDecl True
src/Language/PureScript/Sugar.hs view
@@ -13,15 +13,18 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+ module Language.PureScript.Sugar (desugar, module S) where import Control.Monad import Control.Category ((>>>))-import Control.Monad.Trans.Class+import Control.Applicative+import Control.Monad.Error.Class+import Control.Monad.Supply.Class import Language.PureScript.AST import Language.PureScript.Errors-import Language.PureScript.Supply import Language.PureScript.Sugar.BindingGroups as S import Language.PureScript.Sugar.CaseDeclarations as S@@ -55,14 +58,14 @@ -- -- * Group mutually recursive value and data declarations into binding groups. ---desugar :: [Module] -> SupplyT (Either ErrorStack) [Module]+desugar :: (Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Module] -> m [Module] desugar = map removeSignedLiterals >>> mapM desugarObjectConstructors >=> mapM desugarOperatorSections >=> mapM desugarDoModule >=> desugarCasesModule- >=> lift . (desugarTypeDeclarationsModule- >=> desugarImports- >=> rebracket)+ >=> desugarTypeDeclarationsModule+ >=> desugarImports+ >=> rebracket >=> desugarTypeClasses- >=> lift . createBindingGroupsModule+ >=> createBindingGroupsModule
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -14,6 +14,8 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+ module Language.PureScript.Sugar.BindingGroups ( createBindingGroups, createBindingGroupsModule,@@ -24,8 +26,9 @@ import Data.Graph import Data.List (nub, intersect) import Data.Maybe (isJust, mapMaybe)-import Control.Applicative ((<$>), (<*>), pure)+import Control.Applicative import Control.Monad ((<=<))+import Control.Monad.Error.Class import qualified Data.Set as S @@ -38,29 +41,29 @@ -- | -- Replace all sets of mutually-recursive declarations in a module with binding groups ---createBindingGroupsModule :: [Module] -> Either ErrorStack [Module]-createBindingGroupsModule = mapM $ \(Module name ds exps) -> Module name <$> createBindingGroups name ds <*> pure exps+createBindingGroupsModule :: (Functor m, Applicative m, MonadError MultipleErrors m) => [Module] -> m [Module]+createBindingGroupsModule = mapM $ \(Module coms name ds exps) -> Module coms name <$> createBindingGroups name ds <*> pure exps -- | -- Collapse all binding groups in a module to individual declarations -- collapseBindingGroupsModule :: [Module] -> [Module]-collapseBindingGroupsModule = map $ \(Module name ds exps) -> Module name (collapseBindingGroups ds) exps+collapseBindingGroupsModule = map $ \(Module coms name ds exps) -> Module coms name (collapseBindingGroups ds) exps -createBindingGroups :: ModuleName -> [Declaration] -> Either ErrorStack [Declaration]+createBindingGroups :: (Functor m, Applicative m, MonadError MultipleErrors m) => ModuleName -> [Declaration] -> m [Declaration] createBindingGroups moduleName = mapM f <=< handleDecls where (f, _, _) = everywhereOnValuesTopDownM return handleExprs return - handleExprs :: Expr -> Either ErrorStack Expr+ handleExprs :: (Functor m, MonadError MultipleErrors m) => Expr -> m Expr handleExprs (Let ds val) = flip Let val <$> handleDecls ds handleExprs other = return other -- | -- Replace all sets of mutually-recursive declarations with binding groups --- handleDecls :: [Declaration] -> Either ErrorStack [Declaration]+ handleDecls :: (Functor m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] handleDecls ds = do let values = filter isValueDecl ds dataDecls = filter isDataDecl ds@@ -75,6 +78,7 @@ filter isExternInstanceDecl ds ++ dataBindingGroupDecls ++ filter isTypeClassDeclaration ds +++ filter isTypeClassInstanceDeclaration ds ++ filter isFixityDecl ds ++ filter isExternDecl ds ++ bindingGroupDecls@@ -151,7 +155,7 @@ -- Convert a group of mutually-recursive dependencies into a BindingGroupDeclaration (or simple ValueDeclaration). -- ---toBindingGroup :: ModuleName -> SCC Declaration -> Either ErrorStack Declaration+toBindingGroup :: (Functor m, MonadError MultipleErrors m) => ModuleName -> SCC Declaration -> m Declaration toBindingGroup _ (AcyclicSCC d) = return d toBindingGroup _ (CyclicSCC [d]) = return d toBindingGroup moduleName (CyclicSCC ds') =@@ -172,24 +176,23 @@ valueVerts :: [(Declaration, Ident, [Ident])] valueVerts = map (\d -> (d, getIdent d, usedImmediateIdents moduleName d `intersect` idents)) ds' - toBinding :: SCC Declaration -> Either ErrorStack (Ident, NameKind, Expr)+ toBinding :: (MonadError MultipleErrors m) => SCC Declaration -> m (Ident, NameKind, Expr) toBinding (AcyclicSCC d) = return $ fromValueDecl d toBinding (CyclicSCC ~(d:ds)) = cycleError d ds - cycleError :: Declaration -> [Declaration] -> Either ErrorStack a+ cycleError :: (MonadError MultipleErrors m) => Declaration -> [Declaration] -> m a cycleError (PositionedDeclaration p _ d) ds = rethrowWithPosition p $ cycleError d ds- cycleError (ValueDeclaration n _ _ (Right e)) [] = Left $- mkErrorStack ("Cycle in definition of " ++ show n) (Just (ExprError e))- cycleError d ds@(_:_) = rethrow (mkCompileError ("The following are not yet defined here: " ++ unwords (map (show . getIdent) ds)) Nothing `combineErrors`) $ cycleError d []+ cycleError (ValueDeclaration n _ _ (Right _)) [] = throwError . errorMessage $ CycleInDeclaration n+ cycleError d ds@(_:_) = rethrow (onErrorMessages (NotYetDefined (map getIdent ds))) $ cycleError d [] cycleError _ _ = error "Expected ValueDeclaration" -toDataBindingGroup :: SCC Declaration -> Either ErrorStack Declaration+toDataBindingGroup :: (MonadError MultipleErrors m) => SCC Declaration -> m Declaration toDataBindingGroup (AcyclicSCC d) = return d toDataBindingGroup (CyclicSCC [d]) = case isTypeSynonym d of- Just pn -> Left $ mkErrorStack ("Cycle in type synonym " ++ show pn) Nothing+ Just pn -> throwError . errorMessage $ CycleInTypeSynonym (Just pn) _ -> return d toDataBindingGroup (CyclicSCC ds')- | all (isJust . isTypeSynonym) ds' = Left $ mkErrorStack "Cycle in type synonyms" Nothing+ | all (isJust . isTypeSynonym) ds' = throwError . errorMessage $ CycleInTypeSynonym Nothing | otherwise = return $ DataBindingGroupDeclaration ds' isTypeSynonym :: Declaration -> Maybe ProperName
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -14,6 +14,8 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+ module Language.PureScript.Sugar.CaseDeclarations ( desugarCases, desugarCasesModule@@ -24,12 +26,13 @@ import Control.Applicative import Control.Monad ((<=<), forM, join, unless, replicateM) import Control.Monad.Except (throwError)+import Control.Monad.Error.Class (MonadError)+import Control.Monad.Supply.Class import Language.PureScript.Names import Language.PureScript.AST import Language.PureScript.Environment import Language.PureScript.Errors-import Language.PureScript.Supply import Language.PureScript.Traversals import Language.PureScript.TypeChecker.Monad (guardWith) @@ -41,17 +44,17 @@ -- | -- Replace all top-level binders in a module with case expressions. ---desugarCasesModule :: [Module] -> SupplyT (Either ErrorStack) [Module]-desugarCasesModule ms = forM ms $ \(Module name ds exps) ->- rethrow (mkCompileError ("Error in module " ++ show name) Nothing `combineErrors`) $- Module name <$> (desugarCases <=< desugarAbs $ ds) <*> pure exps+desugarCasesModule :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Module] -> m [Module]+desugarCasesModule ms = forM ms $ \(Module coms name ds exps) ->+ rethrow (onErrorMessages (ErrorInModule name)) $+ Module coms name <$> (desugarCases <=< desugarAbs $ ds) <*> pure exps -desugarAbs :: [Declaration] -> SupplyT (Either ErrorStack) [Declaration]+desugarAbs :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] desugarAbs = flip parU f where (f, _, _) = everywhereOnValuesM return replace return - replace :: Expr -> SupplyT (Either ErrorStack) Expr+ replace :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Expr -> m Expr replace (Abs (Right binder) val) = do ident <- Ident <$> freshName return $ Abs (Left ident) $ Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right val)]@@ -60,10 +63,10 @@ -- | -- Replace all top-level binders with case expressions. ---desugarCases :: [Declaration] -> SupplyT (Either ErrorStack) [Declaration]+desugarCases :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] desugarCases = desugarRest <=< fmap join . flip parU toDecls . groupBy inSameGroup where- desugarRest :: [Declaration] -> SupplyT (Either ErrorStack) [Declaration]+ desugarRest :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] desugarRest (TypeInstanceDeclaration name constraints className tys ds : rest) = (:) <$> (TypeInstanceDeclaration name constraints className tys <$> desugarCases ds) <*> desugarRest rest desugarRest (ValueDeclaration name nameKind bs result : rest) =@@ -86,18 +89,18 @@ inSameGroup d1 (PositionedDeclaration _ _ d2) = inSameGroup d1 d2 inSameGroup _ _ = False -toDecls :: [Declaration] -> SupplyT (Either ErrorStack) [Declaration]+toDecls :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] toDecls [ValueDeclaration ident nameKind bs (Right val)] | all isVarBinder bs = do let args = map (\(VarBinder arg) -> arg) bs body = foldr (Abs . Left) val args- guardWith (strMsg "Overlapping function argument names") $ length (nub args) == length args+ guardWith (errorMessage (OverlappingArgNames (Just ident))) $ length (nub args) == length args return [ValueDeclaration ident nameKind [] (Right body)] toDecls ds@(ValueDeclaration ident _ bs result : _) = do let tuples = map toTuple ds unless (all ((== length bs) . length . fst) tuples) $- throwError $ mkErrorStack ("Argument list lengths differ in declaration " ++ show ident) Nothing+ throwError . errorMessage $ ArgListLengthsDiffer ident unless (not (null bs) || isLeft result) $- throwError $ mkErrorStack ("Duplicate value declaration '" ++ show ident ++ "'") Nothing+ throwError . errorMessage $ DuplicateValueDeclaration ident caseDecl <- makeCaseDeclaration ident tuples return [caseDecl] toDecls (PositionedDeclaration pos com d : ds) = do@@ -114,13 +117,34 @@ toTuple (PositionedDeclaration _ _ d) = toTuple d toTuple _ = error "Not a value declaration" -makeCaseDeclaration :: Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> SupplyT (Either ErrorStack) Declaration+makeCaseDeclaration :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> m Declaration makeCaseDeclaration ident alternatives = do- let argPattern = length . fst . head $ alternatives- args <- map Ident <$> replicateM argPattern freshName+ let namedArgs = map findName . fst <$> alternatives+ args <- mapM argName $ foldl1 resolveNames namedArgs let vars = map (Var . Qualified Nothing) args binders = [ CaseAlternative bs result | (bs, result) <- alternatives ] value = foldr (Abs . Left) (Case vars binders) args return $ ValueDeclaration ident Value [] (Right value)+ where+ findName :: Binder -> Maybe Ident+ findName (VarBinder name) = Just name+ findName (PositionedBinder _ _ binder) = findName binder+ findName _ = Nothing + argName :: (MonadSupply m) => Maybe Ident -> m Ident+ argName (Just name) = return name+ argName Nothing = do+ name <- freshName+ return (Ident name)++ resolveNames :: [Maybe Ident] -> [Maybe Ident] -> [Maybe Ident]+ resolveNames = zipWith resolveName++ resolveName :: Maybe Ident -> Maybe Ident -> Maybe Ident+ resolveName (Just a) (Just b)+ | a == b = Just a+ | otherwise = Nothing+ resolveName Nothing Nothing = Nothing+ resolveName (Just a) Nothing = Just a+ resolveName Nothing (Just b) = Just b
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -14,6 +14,9 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Language.PureScript.Sugar.DoNotation ( desugarDoModule ) where@@ -21,21 +24,21 @@ import Language.PureScript.Names import Language.PureScript.AST import Language.PureScript.Errors-import Language.PureScript.Supply import qualified Language.PureScript.Constants as C import Control.Applicative-import Control.Monad.Trans.Class+import Control.Monad.Error.Class+import Control.Monad.Supply.Class -- | -- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function, -- and all @DoNotationLet@ constructors with let expressions. ---desugarDoModule :: Module -> SupplyT (Either ErrorStack) Module-desugarDoModule (Module mn ds exts) = Module mn <$> parU ds desugarDo <*> pure exts+desugarDoModule :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module+desugarDoModule (Module coms mn ds exts) = Module coms mn <$> parU ds desugarDo <*> pure exts -desugarDo :: Declaration -> SupplyT (Either ErrorStack) Declaration+desugarDo :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Declaration -> m Declaration desugarDo (PositionedDeclaration pos com d) = PositionedDeclaration pos com <$> (rethrowWithPosition pos $ desugarDo d) desugarDo d = let (f, _, _) = everywhereOnValuesM return replace return@@ -47,18 +50,18 @@ bind :: Expr bind = Var (Qualified (Just prelude) (Op (C.>>=))) - replace :: Expr -> SupplyT (Either ErrorStack) Expr+ replace :: Expr -> m Expr replace (Do els) = go els replace (PositionedValue pos com v) = PositionedValue pos com <$> rethrowWithPosition pos (replace v) replace other = return other - go :: [DoNotationElement] -> SupplyT (Either ErrorStack) Expr+ go :: [DoNotationElement] -> m Expr go [] = error "The impossible happened in desugarDo" go [DoNotationValue val] = return val go (DoNotationValue val : rest) = do rest' <- go rest return $ App (App bind val) (Abs (Left (Ident C.__unused)) rest')- go [DoNotationBind _ _] = lift $ Left $ mkErrorStack "Bind statement cannot be the last statement in a do block" Nothing+ go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest) go (DoNotationBind (VarBinder ident) val : rest) = do rest' <- go rest@@ -67,7 +70,7 @@ rest' <- go rest ident <- Ident <$> freshName return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right rest')]))- go [DoNotationLet _] = lift $ Left $ mkErrorStack "Let statement cannot be the last statement in a do block" Nothing+ go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet go (DoNotationLet ds : rest) = do rest' <- go rest return $ Let ds rest'
src/Language/PureScript/Sugar/Names.hs view
@@ -12,6 +12,9 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Language.PureScript.Sugar.Names ( desugarImports ) where@@ -84,7 +87,7 @@ -- Updates the exports for a module from the global environment. If the module was not previously -- present in the global environment, it is created. ---updateExportedModule :: ExportEnvironment -> ModuleName -> (Exports -> Either ErrorStack Exports) -> Either ErrorStack ExportEnvironment+updateExportedModule :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> ModuleName -> (Exports -> m Exports) -> m ExportEnvironment updateExportedModule env mn update = do let exports = fromMaybe (error "Module was undefined in updateExportedModule") $ mn `M.lookup` env exports' <- update exports@@ -93,61 +96,61 @@ -- | -- Adds an empty module to an ExportEnvironment. ---addEmptyModule :: ExportEnvironment -> ModuleName -> Either ErrorStack ExportEnvironment+addEmptyModule :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> ModuleName -> m ExportEnvironment addEmptyModule env name = if name `M.member` env- then throwError $ mkErrorStack ("Module '" ++ show name ++ "' has been defined more than once") Nothing+ then throwError . errorMessage $ RedefinedModule name else return $ M.insert name (Exports [] [] []) env -- | -- Adds a type belonging to a module to the export environment. ---addType :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either ErrorStack ExportEnvironment+addType :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> m ExportEnvironment addType env mn name dctors = updateExportedModule env mn $ \m -> do let exTypes = exportedTypes m let exDctors = snd `concatMap` exTypes let exClasses = exportedTypeClasses m- when (any ((== name) . fst) exTypes) $ throwMultipleDefError "type" name- when (name `elem` exClasses) $ throwConflictingDefError "Type" "type class" name+ when (any ((== name) . fst) exTypes) $ throwConflictError ConflictingTypeDecls name+ when (name `elem` exClasses) $ throwConflictError TypeConflictsWithClass name forM_ dctors $ \dctor -> do- when (dctor `elem` exDctors) $ throwMultipleDefError "data constructor" dctor- when (dctor `elem` exClasses) $ throwConflictingDefError "Data constructor" "type class" dctor+ when (dctor `elem` exDctors) $ throwConflictError ConflictingCtorDecls dctor+ when (dctor `elem` exClasses) $ throwConflictError CtorConflictsWithClass dctor return $ m { exportedTypes = (name, dctors) : exTypes } -- | -- Adds a class to the export environment. ---addTypeClass :: ExportEnvironment -> ModuleName -> ProperName -> Either ErrorStack ExportEnvironment+addTypeClass :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> ModuleName -> ProperName -> m ExportEnvironment addTypeClass env mn name = updateExportedModule env mn $ \m -> do let exTypes = exportedTypes m let exDctors = snd `concatMap` exTypes- when (any ((== name) . fst) exTypes) $ throwConflictingDefError "Type class" "type" name- when (name `elem` exDctors) $ throwConflictingDefError "Type class" "data constructor" name- classes <- addExport "type class" (exportedTypeClasses m) name+ when (any ((== name) . fst) exTypes) $ throwConflictError ClassConflictsWithType name+ when (name `elem` exDctors) $ throwConflictError ClassConflictsWithCtor name+ classes <- addExport DuplicateClassExport (exportedTypeClasses m) name return $ m { exportedTypeClasses = classes } -- | -- Adds a class to the export environment. ---addValue :: ExportEnvironment -> ModuleName -> Ident -> Either ErrorStack ExportEnvironment+addValue :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> ModuleName -> Ident -> m ExportEnvironment addValue env mn name = updateExportedModule env mn $ \m -> do- values <- addExport "value" (exportedValues m) name+ values <- addExport DuplicateValueExport (exportedValues m) name return $ m { exportedValues = values } -- | -- Adds an entry to a list of exports unless it is already present, in which case an error is -- returned. ---addExport :: (Eq a, Show a) => String -> [a] -> a -> Either ErrorStack [a]+addExport :: (Applicative m, MonadError MultipleErrors m, Eq a, Show a) => (a -> ErrorMessage) -> [a] -> a -> m [a] addExport what exports name = if name `elem` exports- then throwMultipleDefError what name+ then throwConflictError what name else return $ name : exports -- | -- Replaces all local names with qualified names within a set of modules. ---desugarImports :: [Module] -> Either ErrorStack [Module]+desugarImports :: forall m. (Applicative m, MonadError MultipleErrors m) => [Module] -> m [Module] desugarImports modules = do unfilteredExports <- findExports modules exports <- foldM filterModuleExports unfilteredExports modules@@ -157,15 +160,15 @@ -- Filters the exports for a module in the global exports environment so that only explicitly -- exported members remain. If the module does not explicitly export anything, everything is -- exported.- filterModuleExports :: ExportEnvironment -> Module -> Either ErrorStack ExportEnvironment- filterModuleExports env (Module mn _ (Just exps)) = filterExports mn exps env+ filterModuleExports :: ExportEnvironment -> Module -> m ExportEnvironment+ filterModuleExports env (Module _ mn _ (Just exps)) = filterExports mn exps env filterModuleExports env _ = return env -- Rename and check all the names within a module. We tweak the global exports environment so -- the module has access to an unfiltered list of its own members.- renameInModule' :: ExportEnvironment -> ExportEnvironment -> Module -> Either ErrorStack Module- renameInModule' unfilteredExports exports m@(Module mn _ _) =- rethrow (mkCompileError ("Error in module " ++ show mn) Nothing `combineErrors`) $ do+ renameInModule' :: ExportEnvironment -> ExportEnvironment -> Module -> m Module+ renameInModule' unfilteredExports exports m@(Module _ mn _ _) =+ rethrow (onErrorMessages (ErrorInModule mn)) $ do let env = M.update (\_ -> M.lookup mn unfilteredExports) mn exports let exps = fromMaybe (error "Module is missing in renameInModule'") $ M.lookup mn exports imports <- resolveImports env m@@ -176,7 +179,7 @@ -- as it will also make all data constructor exports explicit. -- elaborateExports :: Exports -> Module -> Module-elaborateExports exps (Module mn decls _) = Module mn decls (Just $+elaborateExports exps (Module coms mn decls _) = Module coms mn decls (Just $ map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) (exportedTypes exps) ++ map TypeClassRef (exportedTypeClasses exps) ++ map ValueRef (exportedValues exps))@@ -186,7 +189,7 @@ -- This ensures transitive instances are included when using a member from a module. -- elaborateImports :: Module -> Module-elaborateImports (Module mn decls exps) = Module mn decls' exps+elaborateImports (Module coms mn decls exps) = Module coms mn decls' exps where decls' :: [Declaration] decls' =@@ -196,19 +199,19 @@ fqValues (Var (Qualified (Just mn') _)) = [mn'] fqValues _ = [] mkImport :: ModuleName -> Declaration- mkImport mn' = ImportDeclaration mn' (Qualifying []) Nothing+ mkImport mn' = ImportDeclaration mn' (Explicit []) Nothing -- | -- Replaces all local names with qualified names within a module and checks that all existing -- qualified names are valid. ---renameInModule :: ImportEnvironment -> ExportEnvironment -> Module -> Either ErrorStack Module-renameInModule imports exports (Module mn decls exps) =- Module mn <$> parU decls go <*> pure exps+renameInModule :: forall m. (Applicative m, MonadError MultipleErrors m) => ImportEnvironment -> ExportEnvironment -> Module -> m Module+renameInModule imports exports (Module coms mn decls exps) =+ Module coms mn <$> parU decls go <*> pure exps where (go, _, _, _, _) = everywhereWithContextOnValuesM (Nothing, []) updateDecl updateValue updateBinder updateCase defS - updateDecl :: (Maybe SourceSpan, [Ident]) -> Declaration -> Either ErrorStack ((Maybe SourceSpan, [Ident]), Declaration)+ updateDecl :: (Maybe SourceSpan, [Ident]) -> Declaration -> m ((Maybe SourceSpan, [Ident]), Declaration) updateDecl (_, bound) d@(PositionedDeclaration pos _ _) = return ((Just pos, bound), d) updateDecl (pos, bound) (DataDeclaration dtype name args dctors) = (,) (pos, bound) <$> (DataDeclaration dtype name args <$> mapM (sndM (mapM (updateTypesEverywhere pos))) dctors)@@ -226,14 +229,14 @@ (,) (pos, name : bound) <$> (ExternDeclaration fit name js <$> updateTypesEverywhere pos ty) updateDecl s d = return (s, d) - updateValue :: (Maybe SourceSpan, [Ident]) -> Expr -> Either ErrorStack ((Maybe SourceSpan, [Ident]), Expr)+ updateValue :: (Maybe SourceSpan, [Ident]) -> Expr -> m ((Maybe SourceSpan, [Ident]), Expr) updateValue (_, bound) v@(PositionedValue pos' _ _) = return ((Just pos', bound), v) updateValue (pos, bound) (Abs (Left arg) val') = return ((pos, arg : bound), Abs (Left arg) val') updateValue (pos, bound) (Let ds val') = do let args = mapMaybe letBoundVariable ds unless (length (nub args) == length args) $- maybe id rethrowWithPosition pos $ - throwError $ mkErrorStack ("Overlapping names in let binding.") Nothing+ maybe id rethrowWithPosition pos $+ throwError . errorMessage $ OverlappingNamesInLet return ((pos, args ++ bound), Let ds val') where updateValue (pos, bound) (Var name'@(Qualified Nothing ident)) | ident `notElem` bound =@@ -244,12 +247,12 @@ updateValue s@(pos, _) (TypedValue check val ty) = (,) s <$> (TypedValue check val <$> updateTypesEverywhere pos ty) updateValue s v = return (s, v) - updateBinder :: (Maybe SourceSpan, [Ident]) -> Binder -> Either ErrorStack ((Maybe SourceSpan, [Ident]), Binder)+ updateBinder :: (Maybe SourceSpan, [Ident]) -> Binder -> m ((Maybe SourceSpan, [Ident]), Binder) updateBinder (_, bound) v@(PositionedBinder pos _ _) = return ((Just pos, bound), v) updateBinder s@(pos, _) (ConstructorBinder name b) = (,) s <$> (ConstructorBinder <$> updateDataConstructorName name pos <*> pure b) updateBinder s v = return (s, v) - updateCase :: (Maybe SourceSpan, [Ident]) -> CaseAlternative -> Either ErrorStack ((Maybe SourceSpan, [Ident]), CaseAlternative)+ updateCase :: (Maybe SourceSpan, [Ident]) -> CaseAlternative -> m ((Maybe SourceSpan, [Ident]), CaseAlternative) updateCase (pos, bound) c@(CaseAlternative bs _) = return ((pos, concatMap binderNames bs ++ bound), c) letBoundVariable :: Declaration -> Maybe Ident@@ -257,10 +260,10 @@ letBoundVariable (PositionedDeclaration _ _ d) = letBoundVariable d letBoundVariable _ = Nothing - updateTypesEverywhere :: Maybe SourceSpan -> Type -> Either ErrorStack Type+ updateTypesEverywhere :: Maybe SourceSpan -> Type -> m Type updateTypesEverywhere pos0 = everywhereOnTypesM (updateType pos0) where- updateType :: Maybe SourceSpan -> Type -> Either ErrorStack Type+ updateType :: Maybe SourceSpan -> Type -> m Type updateType pos (TypeConstructor name) = TypeConstructor <$> updateTypeName name pos updateType pos (SaturatedTypeSynonym name tys) = SaturatedTypeSynonym <$> updateTypeName name pos <*> pure tys updateType pos (ConstrainedType cs t) = ConstrainedType <$> updateConstraints pos cs <*> pure t@@ -268,28 +271,28 @@ updateConstraints pos = mapM (\(name, ts) -> (,) <$> updateClassName name pos <*> mapM (updateTypesEverywhere pos) ts) - updateTypeName = update "type" importedTypes (\mes -> isJust . (`lookup` exportedTypes mes))- updateClassName = update "type class" importedTypeClasses (flip elem . exportedTypeClasses)- updateValueName = update "value" importedValues (flip elem . exportedValues)- updateDataConstructorName = update "data constructor" importedDataConstructors (\mes -> flip elem (join $ snd `map` exportedTypes mes))+ updateTypeName = update UnknownType importedTypes (\mes -> isJust . (`lookup` exportedTypes mes))+ updateClassName = update UnknownTypeClass importedTypeClasses (flip elem . exportedTypeClasses)+ updateValueName = update UnknownValue importedValues (flip elem . exportedValues)+ updateDataConstructorName = update (flip UnknownDataConstructor Nothing) importedDataConstructors (\mes -> flip elem (join $ snd `map` exportedTypes mes)) -- Update names so unqualified references become qualified, and locally qualified references -- are replaced with their canoncial qualified names (e.g. M.Map -> Data.Map.Map)- update :: (Ord a, Show a) => String+ update :: (Ord a, Show a) => (Qualified a -> ErrorMessage) -> (ImportEnvironment -> M.Map (Qualified a) (Qualified a)) -> (Exports -> a -> Bool) -> Qualified a -> Maybe SourceSpan- -> Either ErrorStack (Qualified a)- update t getI checkE qname@(Qualified mn' name) pos = positioned $ case (M.lookup qname imports', mn') of+ -> m (Qualified a)+ update unknown getI checkE qname@(Qualified mn' name) pos = positioned $ case (M.lookup qname imports', mn') of (Just qname', _) -> return qname' (Nothing, Just mn'') -> do- when (isExplicitQualModule mn'') $ throwError $ mkErrorStack ("Unknown " ++ t ++ " '" ++ show qname ++ "'") Nothing+ when (isExplicitQualModule mn'') . throwError . errorMessage $ unknown qname modExports <- getExports mn'' if checkE modExports name then return qname- else throwError $ mkErrorStack ("Unknown " ++ t ++ " '" ++ show qname ++ "'") Nothing- _ -> throwError $ mkErrorStack ("Unknown " ++ t ++ " '" ++ show name ++ "'") Nothing+ else throwError . errorMessage $ unknown qname+ _ -> throwError . errorMessage $ unknown qname where isExplicitQualModule :: ModuleName -> Bool isExplicitQualModule = flip elem $ mapMaybe (\(Qualified q _) -> q) (M.keys imports')@@ -299,13 +302,13 @@ Just pos' -> rethrowWithPosition pos' err -- Gets the exports for a module, or an error message if the module doesn't exist- getExports :: ModuleName -> Either ErrorStack Exports- getExports mn' = maybe (throwError $ mkErrorStack ("Unknown module '" ++ show mn' ++ "'") Nothing) return $ M.lookup mn' exports+ getExports :: ModuleName -> m Exports+ getExports mn' = maybe (throwError . errorMessage $ UnknownModule mn') return $ M.lookup mn' exports -- | -- Finds all exported declarations in a set of modules. ---findExports :: [Module] -> Either ErrorStack ExportEnvironment+findExports :: forall m. (Applicative m, MonadError MultipleErrors m) => [Module] -> m ExportEnvironment findExports = foldM addModule $ M.singleton (ModuleName [ProperName C.prim]) primExports where @@ -315,13 +318,13 @@ mkTypeEntry (Qualified _ name) = (name, []) -- Add all of the exported declarations from a module to the global export environment- addModule :: ExportEnvironment -> Module -> Either ErrorStack ExportEnvironment- addModule env (Module mn ds _) = do+ addModule :: ExportEnvironment -> Module -> m ExportEnvironment+ addModule env (Module _ mn ds _) = do env' <- addEmptyModule env mn- rethrow (mkCompileError ("Error in module " ++ show mn) Nothing `combineErrors`) $ foldM (addDecl mn) env' ds+ rethrow (onErrorMessages (ErrorInModule mn)) $ foldM (addDecl mn) env' ds -- Add a declaration from a module to the global export environment- addDecl :: ModuleName -> ExportEnvironment -> Declaration -> Either ErrorStack ExportEnvironment+ addDecl :: ModuleName -> ExportEnvironment -> Declaration -> m ExportEnvironment addDecl mn env (TypeClassDeclaration tcn _ _ ds) = do env' <- addTypeClass env mn tcn foldM go env' ds@@ -341,15 +344,15 @@ -- Filters the exports for a module to ensure only explicit exports are kept in the global exports -- environment. ---filterExports :: ModuleName -> [DeclarationRef] -> ExportEnvironment -> Either ErrorStack ExportEnvironment+filterExports :: forall m. (Applicative m, MonadError MultipleErrors m) => ModuleName -> [DeclarationRef] -> ExportEnvironment -> m ExportEnvironment filterExports mn exps env = do let moduleExports = fromMaybe (error "Module is missing") (mn `M.lookup` env)- moduleExports' <- rethrow (mkCompileError ("Error in module " ++ show mn) Nothing `combineErrors`) $ filterModule moduleExports+ moduleExports' <- rethrow (onErrorMessages (ErrorInModule mn)) $ filterModule moduleExports return $ M.insert mn moduleExports' env where -- Filter the exports for the specific module- filterModule :: Exports -> Either ErrorStack Exports+ filterModule :: Exports -> m Exports filterModule exported = do types' <- foldM (filterTypes $ exportedTypes exported) [] exps values <- foldM (filterValues $ exportedValues exported) [] exps@@ -358,37 +361,37 @@ -- Ensure the exported types and data constructors exist in the module and add them to the set of -- exports- filterTypes :: [(ProperName, [ProperName])] -> [(ProperName, [ProperName])] -> DeclarationRef -> Either ErrorStack [(ProperName, [ProperName])]+ filterTypes :: [(ProperName, [ProperName])] -> [(ProperName, [ProperName])] -> DeclarationRef -> m [(ProperName, [ProperName])] filterTypes expTys result (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ filterTypes expTys result r filterTypes expTys result (TypeRef name expDcons) = do- dcons <- maybe (throwError $ mkErrorStack ("Cannot export undefined type '" ++ show name ++ "'") Nothing) return $ name `lookup` expTys+ dcons <- maybe (throwError . errorMessage . UnknownType $ Qualified (Just mn) name) return $ name `lookup` expTys dcons' <- maybe (return dcons) (foldM (filterDcons name dcons) []) expDcons return $ (name, dcons') : result filterTypes _ result _ = return result -- Ensure the exported data constructors exists for a type and add them to the list of exports- filterDcons :: ProperName -> [ProperName] -> [ProperName] -> ProperName -> Either ErrorStack [ProperName]+ filterDcons :: ProperName -> [ProperName] -> [ProperName] -> ProperName -> m [ProperName] filterDcons tcon exps' result name = if name `elem` exps' then return $ name : result- else throwError $ mkErrorStack ("Cannot export undefined data constructor '" ++ show name ++ "' for type '" ++ show tcon ++ "'") Nothing+ else throwError . errorMessage $ UnknownDataConstructor (Qualified (Just mn) name) (Just (Qualified (Just mn) tcon)) -- Ensure the exported classes exist in the module and add them to the set of exports- filterClasses :: [ProperName] -> [ProperName] -> DeclarationRef -> Either ErrorStack [ProperName]+ filterClasses :: [ProperName] -> [ProperName] -> DeclarationRef -> m [ProperName] filterClasses exps' result (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ filterClasses exps' result r filterClasses exps' result (TypeClassRef name) = if name `elem` exps' then return $ name : result- else throwError $ mkErrorStack ("Cannot export undefined type class '" ++ show name ++ "'") Nothing+ else throwError . errorMessage . UnknownTypeClass $ Qualified (Just mn) name filterClasses _ result _ = return result -- Ensure the exported values exist in the module and add them to the set of exports- filterValues :: [Ident] -> [Ident] -> DeclarationRef -> Either ErrorStack [Ident]+ filterValues :: [Ident] -> [Ident] -> DeclarationRef -> m [Ident] filterValues exps' result (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ filterValues exps' result r filterValues exps' result (ValueRef name) = if name `elem` exps' then return $ name : result- else throwError $ mkErrorStack ("Cannot export undefined value '" ++ show name ++ "'") Nothing+ else throwError . errorMessage . UnknownValue $ Qualified (Just mn) name filterValues _ result _ = return result -- |@@ -405,8 +408,8 @@ -- | -- Constructs a local environment for a module. ---resolveImports :: ExportEnvironment -> Module -> Either ErrorStack ImportEnvironment-resolveImports env (Module currentModule decls _) =+resolveImports :: forall m. (Applicative m, MonadError MultipleErrors m) => ExportEnvironment -> Module -> m ImportEnvironment+resolveImports env (Module _ currentModule decls _) = foldM resolveImport' (ImportEnvironment M.empty M.empty M.empty M.empty) (M.toList scope) where @@ -414,11 +417,11 @@ -- module (where Nothing indicates everything is to be imported), and optionally a qualified name -- for the module scope :: M.Map ModuleName (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)- scope = M.insert currentModule (Nothing, Unqualified, Nothing) (findImports decls)+ scope = M.insert currentModule (Nothing, Implicit, Nothing) (findImports decls) - resolveImport' :: ImportEnvironment -> (ModuleName, (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)) -> Either ErrorStack ImportEnvironment+ resolveImport' :: ImportEnvironment -> (ModuleName, (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)) -> m ImportEnvironment resolveImport' imp (mn, (pos, typ, impQual)) = do- modExports <- positioned $ maybe (throwError $ mkErrorStack ("Cannot import unknown module '" ++ show mn ++ "'") Nothing) return $ mn `M.lookup` env+ modExports <- positioned $ maybe (throwError . errorMessage $ UnknownModule mn) return $ mn `M.lookup` env positioned $ resolveImport currentModule mn modExports imp impQual typ where positioned err = case pos of@@ -428,19 +431,19 @@ -- | -- Extends the local environment for a module by resolving an import of another module. ---resolveImport :: ModuleName -> ModuleName -> Exports -> ImportEnvironment -> Maybe ModuleName -> ImportDeclarationType -> Either ErrorStack ImportEnvironment+resolveImport :: forall m. (Applicative m, MonadError MultipleErrors m) => ModuleName -> ModuleName -> Exports -> ImportEnvironment -> Maybe ModuleName -> ImportDeclarationType -> m ImportEnvironment resolveImport currentModule importModule exps imps impQual = resolveByType where - resolveByType :: ImportDeclarationType -> Either ErrorStack ImportEnvironment- resolveByType Unqualified = importAll importExplicit- resolveByType (Qualifying explImports) = (checkedRefs >=> foldM importExplicit imps) explImports+ resolveByType :: ImportDeclarationType -> m ImportEnvironment+ resolveByType Implicit = importAll importExplicit+ resolveByType (Explicit explImports) = (checkedRefs >=> foldM importExplicit imps) explImports resolveByType (Hiding hiddenImports) = do hiddenImports' <- checkedRefs hiddenImports importAll (importNonHidden hiddenImports') - importNonHidden :: [DeclarationRef] -> ImportEnvironment -> DeclarationRef -> Either ErrorStack ImportEnvironment+ importNonHidden :: [DeclarationRef] -> ImportEnvironment -> DeclarationRef -> m ImportEnvironment importNonHidden hidden m ref = if isHidden hidden ref then return m@@ -459,14 +462,14 @@ isHidden hidden ref = ref `elem` hidden -- Import all symbols- importAll :: (ImportEnvironment -> DeclarationRef -> Either ErrorStack ImportEnvironment) -> Either ErrorStack ImportEnvironment+ importAll :: (ImportEnvironment -> DeclarationRef -> m ImportEnvironment) -> m ImportEnvironment importAll importer = do imp' <- foldM (\m (name, dctors) -> importer m (TypeRef name (Just dctors))) imps (exportedTypes exps) imp'' <- foldM (\m name -> importer m (ValueRef name)) imp' (exportedValues exps) foldM (\m name -> importer m (TypeClassRef name)) imp'' (exportedTypeClasses exps) -- Import something explicitly- importExplicit :: ImportEnvironment -> DeclarationRef -> Either ErrorStack ImportEnvironment+ importExplicit :: ImportEnvironment -> DeclarationRef -> m ImportEnvironment importExplicit imp (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ importExplicit imp r importExplicit imp (ValueRef name) = do values' <- updateImports (importedValues imp) name@@ -483,20 +486,20 @@ importExplicit _ _ = error "Invalid argument to importExplicit" -- Check if DeclarationRef points to an existent symbol- checkedRefs :: [DeclarationRef] -> Either ErrorStack [DeclarationRef]+ checkedRefs :: [DeclarationRef] -> m [DeclarationRef] checkedRefs = mapM check where check (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ check r check ref@(ValueRef name) =- checkImportExists "value" values name >> return ref+ checkImportExists UnknownValue values name >> return ref check ref@(TypeRef name dctors) = do- _ <- checkImportExists "type" availableTypes name+ _ <- checkImportExists UnknownType availableTypes name let allDctors = allExportedDataConstructors name _ <- maybe (return allDctors) (mapM $ checkDctorExists allDctors) dctors return ref check ref@(TypeClassRef name) =- checkImportExists "type class" classes name >> return ref+ checkImportExists UnknownTypeClass classes name >> return ref check _ = error "Invalid argument to checkRefIsValid" -- Find all exported data constructors for a given type@@ -504,15 +507,15 @@ allExportedDataConstructors name = fromMaybe [] $ name `lookup` exportedTypes exps -- Add something to the ImportEnvironment if it does not already exist there- updateImports :: (Ord a, Show a) => M.Map (Qualified a) (Qualified a) -> a -> Either ErrorStack (M.Map (Qualified a) (Qualified a))+ updateImports :: (Ord a, Show a) => M.Map (Qualified a) (Qualified a) -> a -> m (M.Map (Qualified a) (Qualified a)) updateImports m name = case M.lookup (Qualified impQual name) m of Nothing -> return $ M.insert (Qualified impQual name) (Qualified (Just importModule) name) m Just (Qualified Nothing _) -> error "Invalid state in updateImports"- Just x@(Qualified (Just mn) _) -> throwError $ mkErrorStack err Nothing+ Just (Qualified (Just mn) _) -> throwError . errorMessage $ err where err = if mn == currentModule || importModule == currentModule- then "Definition '" ++ show name ++ "' conflicts with import '" ++ show (Qualified (Just mn) name) ++ "'"- else "Conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just importModule) name) ++ "'"+ then ConflictingImport (show name) mn+ else ConflictingImports (show name) mn importModule -- The available values, types, and classes in the module being imported values = exportedValues exps@@ -521,28 +524,18 @@ -- Ensure that an explicitly imported data constructor exists for the type it is being imported -- from- checkDctorExists :: [ProperName] -> ProperName -> Either ErrorStack ProperName- checkDctorExists = checkImportExists "data constructor"+ checkDctorExists :: [ProperName] -> ProperName -> m ProperName+ checkDctorExists = checkImportExists (flip UnknownDataConstructor Nothing) -- Check that an explicitly imported item exists in the module it is being imported from- checkImportExists :: (Eq a, Show a) => String -> [a] -> a -> Either ErrorStack a- checkImportExists t exports item =+ checkImportExists :: (Eq a, Show a) => (Qualified a -> ErrorMessage) -> [a] -> a -> m a+ checkImportExists unknown exports item = if item `elem` exports then return item- else throwError $ mkErrorStack ("Cannot import unknown " ++ t ++ " '" ++ show item ++ "' from '" ++ show importModule ++ "'") Nothing+ else throwError . errorMessage . unknown $ Qualified (Just importModule) item -- | -- Raises an error for when there is more than one definition for something. ---throwMultipleDefError :: (Show a) => String -> a -> Either ErrorStack b-throwMultipleDefError what name = throwError $- mkErrorStack ("Multiple definitions for " ++ what ++ " '" ++ show name ++ "'") Nothing---- |--- Raises an error for when there is a conflicting definition for something, for example, a type--- class and data constructor of the same name.----throwConflictingDefError :: (Show a) => String -> String -> a -> Either ErrorStack b-throwConflictingDefError what1 what2 name = throwError $- mkErrorStack (what1 ++ " '" ++ show name ++ "' cannot be defined in the same module as a " ++ what2 ++ " of the same name") Nothing-+throwConflictError :: (Applicative m, MonadError MultipleErrors m, Show a) => (a -> ErrorMessage) -> a -> m b+throwConflictError conflict = throwError . errorMessage . conflict
src/Language/PureScript/Sugar/ObjectWildcards.hs view
@@ -12,12 +12,17 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Language.PureScript.Sugar.ObjectWildcards ( desugarObjectConstructors ) where import Control.Applicative import Control.Arrow (second)+import Control.Monad.Error.Class+import Control.Monad.Supply.Class import Data.List (partition) import Data.Maybe (isJust, fromJust, catMaybes)@@ -25,16 +30,15 @@ import Language.PureScript.AST import Language.PureScript.Errors import Language.PureScript.Names-import Language.PureScript.Supply -desugarObjectConstructors :: Module -> SupplyT (Either ErrorStack) Module-desugarObjectConstructors (Module mn ds exts) = Module mn <$> mapM desugarDecl ds <*> pure exts+desugarObjectConstructors :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module+desugarObjectConstructors (Module coms mn ds exts) = Module coms mn <$> mapM desugarDecl ds <*> pure exts where - desugarDecl :: Declaration -> SupplyT (Either ErrorStack) Declaration+ desugarDecl :: Declaration -> m Declaration (desugarDecl, _, _) = everywhereOnValuesM return desugarExpr return - desugarExpr :: Expr -> SupplyT (Either ErrorStack) Expr+ desugarExpr :: Expr -> m Expr desugarExpr (ObjectConstructor ps) = wrapLambda ObjectLiteral ps desugarExpr (ObjectUpdater (Just obj) ps) = wrapLambda (ObjectUpdate obj) ps desugarExpr (ObjectUpdater Nothing ps) = do@@ -45,7 +49,7 @@ return $ Abs (Left arg) (Accessor prop (Var (Qualified Nothing arg))) desugarExpr e = return e - wrapLambda :: ([(String, Expr)] -> Expr) -> [(String, Maybe Expr)] -> SupplyT (Either ErrorStack) Expr+ wrapLambda :: ([(String, Expr)] -> Expr) -> [(String, Maybe Expr)] -> m Expr wrapLambda mkVal ps = let (props, args) = partition (isJust . snd) ps in if null args@@ -54,7 +58,7 @@ (args', ps') <- unzip <$> mapM mkProp ps return $ foldr (Abs . Left) (mkVal ps') (catMaybes args') - mkProp :: (String, Maybe Expr) -> SupplyT (Either ErrorStack) (Maybe Ident, (String, Expr))+ mkProp :: (String, Maybe Expr) -> m (Maybe Ident, (String, Expr)) mkProp (name, Just e) = return (Nothing, (name, e)) mkProp (name, Nothing) = do arg <- Ident <$> freshName
src/Language/PureScript/Sugar/Operators.hs view
@@ -17,7 +17,9 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE Rank2Types, FlexibleContexts #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-} module Language.PureScript.Sugar.Operators ( rebracket,@@ -28,11 +30,11 @@ import Language.PureScript.AST import Language.PureScript.Errors import Language.PureScript.Names-import Language.PureScript.Supply import Control.Applicative import Control.Monad.State import Control.Monad.Except+import Control.Monad.Supply.Class import Data.Function (on) import Data.Functor.Identity@@ -47,7 +49,7 @@ -- | -- Remove explicit parentheses and reorder binary operator applications ---rebracket :: [Module] -> Either ErrorStack [Module]+rebracket :: (Applicative m, MonadError MultipleErrors m) => [Module] -> m [Module] rebracket ms = do let fixities = concatMap collectFixities ms ensureNoDuplicates $ map (\(i, pos, _) -> (i, pos)) fixities@@ -55,17 +57,17 @@ mapM (rebracketModule opTable) ms removeSignedLiterals :: Module -> Module-removeSignedLiterals (Module mn ds exts) = Module mn (map f' ds) exts+removeSignedLiterals (Module coms mn ds exts) = Module coms mn (map f' ds) exts where (f', _, _) = everywhereOnValues id go id go (UnaryMinus val) = App (Var (Qualified (Just (ModuleName [ProperName C.prelude])) (Ident C.negate))) val go other = other -rebracketModule :: [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Module -> Either ErrorStack Module-rebracketModule opTable (Module mn ds exts) =+rebracketModule :: (Applicative m, MonadError MultipleErrors m) => [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Module -> m Module+rebracketModule opTable (Module coms mn ds exts) = let (f, _, _) = everywhereOnValuesTopDownM return (matchOperators opTable) return- in Module mn <$> (map removeParens <$> parU ds f) <*> pure exts+ in Module coms mn <$> (map removeParens <$> parU ds f) <*> pure exts removeParens :: Declaration -> Declaration removeParens =@@ -76,22 +78,22 @@ go val = val collectFixities :: Module -> [(Qualified Ident, SourceSpan, Fixity)]-collectFixities (Module moduleName ds _) = concatMap collect ds+collectFixities (Module _ moduleName ds _) = concatMap collect ds where collect :: Declaration -> [(Qualified Ident, SourceSpan, Fixity)] collect (PositionedDeclaration pos _ (FixityDeclaration fixity name)) = [(Qualified (Just moduleName) (Op name), pos, fixity)] collect FixityDeclaration{} = error "Fixity without srcpos info" collect _ = [] -ensureNoDuplicates :: [(Qualified Ident, SourceSpan)] -> Either ErrorStack ()+ensureNoDuplicates :: (MonadError MultipleErrors m) => [(Qualified Ident, SourceSpan)] -> m () ensureNoDuplicates m = go $ sortBy (compare `on` fst) m where go [] = return () go [_] = return () go ((x@(Qualified (Just mn) name), _) : (y, pos) : _) | x == y =- rethrow (mkCompileError ("Error in module " ++ show mn) Nothing `combineErrors`) $+ rethrow (onErrorMessages (ErrorInModule mn)) $ rethrowWithPosition pos $- throwError $ mkErrorStack ("Redefined fixity for " ++ show name) Nothing+ throwError . errorMessage $ MultipleFixities name go (_ : rest) = go rest customOperatorTable :: [(Qualified Ident, Fixity)] -> [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]]@@ -106,17 +108,17 @@ type Chain = [Either Expr Expr] -matchOperators :: [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Expr -> Either ErrorStack Expr+matchOperators :: forall m. (MonadError MultipleErrors m) => [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Expr -> m Expr matchOperators ops = parseChains where- parseChains :: Expr -> Either ErrorStack Expr+ parseChains :: Expr -> m Expr parseChains b@BinaryNoParens{} = bracketChain (extendChain b) parseChains other = return other extendChain :: Expr -> Chain extendChain (BinaryNoParens op l r) = Left l : Right op : extendChain r extendChain other = [Left other]- bracketChain :: Chain -> Either ErrorStack Expr- bracketChain = either (Left . (`mkErrorStack` Nothing) . show) Right . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression"+ bracketChain :: Chain -> m Expr+ bracketChain = either (const . throwError . errorMessage $ CannotReorderOperators) return . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression" opTable = [P.Infix (P.try (parseTicks >>= \op -> return (\t1 t2 -> App (App op t1) t2))) P.AssocLeft] : map (map (\(name, f, a) -> P.Infix (P.try (matchOp name) >> return f) (toAssoc a))) ops ++ [[ P.Infix (P.try (parseOp >>= \ident -> return (\t1 t2 -> App (App (Var ident) t1) t2))) P.AssocLeft ]]@@ -149,14 +151,14 @@ ident <- parseOp guard $ ident == op -desugarOperatorSections :: Module -> SupplyT (Either ErrorStack) Module-desugarOperatorSections (Module mn ds exts) = Module mn <$> mapM goDecl ds <*> pure exts+desugarOperatorSections :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module+desugarOperatorSections (Module coms mn ds exts) = Module coms mn <$> mapM goDecl ds <*> pure exts where - goDecl :: Declaration -> SupplyT (Either ErrorStack) Declaration+ goDecl :: Declaration -> m Declaration (goDecl, _, _) = everywhereOnValuesM return goExpr return - goExpr :: Expr -> SupplyT (Either ErrorStack) Expr+ goExpr :: Expr -> m Expr goExpr (OperatorSection op (Left val)) = return $ App op val goExpr (OperatorSection op (Right val)) = do arg <- Ident <$> freshName
src/Language/PureScript/Sugar/TypeClasses.hs view
@@ -14,6 +14,8 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+ module Language.PureScript.Sugar.TypeClasses ( desugarTypeClasses , typeClassMemberName@@ -25,9 +27,8 @@ import Language.PureScript.Errors import Language.PureScript.Kinds import Language.PureScript.Names-import Language.PureScript.Pretty.Types (prettyPrintTypeAtom) import Language.PureScript.Sugar.CaseDeclarations-import Language.PureScript.Supply+import Control.Monad.Supply.Class import Language.PureScript.Types import qualified Language.PureScript.Constants as C@@ -36,26 +37,32 @@ import Control.Arrow (first, second) import Control.Monad.Except import Control.Monad.State-import Data.List ((\\), find)+import Data.List ((\\), find, sortBy) import Data.Maybe (catMaybes, mapMaybe, isJust) import qualified Data.Map as M type MemberMap = M.Map (ModuleName, ProperName) Declaration -type Desugar = StateT MemberMap (SupplyT (Either ErrorStack))+type Desugar = StateT MemberMap -- | -- Add type synonym declarations for type class dictionary types, and value declarations for type class -- instance dictionary expressions. ---desugarTypeClasses :: [Module] -> SupplyT (Either ErrorStack) [Module]+desugarTypeClasses :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Module] -> m [Module] desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule -desugarModule :: Module -> Desugar Module-desugarModule (Module name decls (Just exps)) = do- (newExpss, declss) <- unzip <$> parU decls (desugarDecl name exps)- return $ Module name (concat declss) $ Just (exps ++ catMaybes newExpss)+desugarModule :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> Desugar m Module+desugarModule (Module coms name decls (Just exps)) = do+ (newExpss, declss) <- unzip <$> parU (sortBy classesFirst decls) (desugarDecl name exps)+ return $ Module coms name (concat declss) $ Just (exps ++ catMaybes newExpss)+ where+ classesFirst :: Declaration -> Declaration -> Ordering+ classesFirst d1 d2 + | isTypeClassDeclaration d1 && not (isTypeClassDeclaration d2) = LT+ | not (isTypeClassDeclaration d1) && isTypeClassDeclaration d2 = GT+ | otherwise = EQ desugarModule _ = error "Exports should have been elaborated in name desugaring" {- Desugar type class and type class instance declarations@@ -152,7 +159,7 @@ -- return new Sub(fooString, ""); -- }; -}-desugarDecl :: ModuleName -> [DeclarationRef] -> Declaration -> Desugar (Maybe DeclarationRef, [Declaration])+desugarDecl :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => ModuleName -> [DeclarationRef] -> Declaration -> Desugar m (Maybe DeclarationRef, [Declaration]) desugarDecl mn exps = go where go d@(TypeClassDeclaration name args implies members) = do@@ -160,7 +167,7 @@ return (Nothing, d : typeClassDictionaryDeclaration name args implies members : map (typeClassMemberToDictionaryAccessor mn name args) members) go d@(ExternInstanceDeclaration name _ className tys) = return (expRef name className tys, [d]) go d@(TypeInstanceDeclaration name deps className tys members) = do- desugared <- lift $ desugarCases members+ desugared <- desugarCases members dictDecl <- typeInstanceDictionaryDeclaration name mn deps className tys desugared return (expRef name className tys, [d, dictDecl]) go (PositionedDeclaration pos com d) = do@@ -222,18 +229,18 @@ unit :: Type unit = TypeApp tyObject REmpty -typeInstanceDictionaryDeclaration :: Ident -> ModuleName -> [Constraint] -> Qualified ProperName -> [Type] -> [Declaration] -> Desugar Declaration+typeInstanceDictionaryDeclaration :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Ident -> ModuleName -> [Constraint] -> Qualified ProperName -> [Type] -> [Declaration] -> Desugar m Declaration typeInstanceDictionaryDeclaration name mn deps className tys decls =- rethrow (mkCompileError ("Error in type class instance " ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys) ++ ":") Nothing `combineErrors`) $ do+ rethrow (onErrorMessages (ErrorInInstance className tys)) $ do m <- get -- Lookup the type arguments and member types for the type class- (TypeClassDeclaration _ args implies tyDecls) <- lift . lift $- maybe (Left $ mkErrorStack ("Type class " ++ show className ++ " is undefined") Nothing) Right $+ (TypeClassDeclaration _ args implies tyDecls) <-+ maybe (throwError . errorMessage $ UnknownTypeClass className) return $ M.lookup (qualify mn className) m case mapMaybe declName tyDecls \\ mapMaybe declName decls of- x : _ -> throwError $ mkErrorStack ("Member '" ++ show x ++ "' has not been implemented") Nothing+ member : _ -> throwError . errorMessage $ MissingClassMember member [] -> do let instanceTys = map memberToNameAndType tyDecls@@ -268,9 +275,9 @@ declName (TypeDeclaration ident _) = Just ident declName _ = Nothing - memberToValue :: [(Ident, Type)] -> Declaration -> Desugar Expr+ memberToValue :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [(Ident, Type)] -> Declaration -> Desugar m Expr memberToValue tys' (ValueDeclaration ident _ [] (Right val)) = do- _ <- lift . lift . maybe (Left $ mkErrorStack ("Type class does not define member '" ++ show ident ++ "'") Nothing) Right $ lookup ident tys'+ _ <- maybe (throwError . errorMessage $ MissingClassMember ident) return $ lookup ident tys' return val memberToValue tys' (PositionedDeclaration pos com d) = rethrowWithPosition pos $ do val <- memberToValue tys' d
src/Language/PureScript/Sugar/TypeDeclarations.hs view
@@ -14,6 +14,8 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-}+ module Language.PureScript.Sugar.TypeDeclarations ( desugarTypeDeclarations, desugarTypeDeclarationsModule@@ -22,6 +24,7 @@ import Control.Applicative import Control.Monad (forM) import Control.Monad.Except (throwError)+import Control.Monad.Error.Class (MonadError) import Language.PureScript.AST import Language.PureScript.Names@@ -32,15 +35,15 @@ -- | -- Replace all top level type declarations in a module with type annotations ---desugarTypeDeclarationsModule :: [Module] -> Either ErrorStack [Module]-desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds exps) ->- rethrow (mkCompileError ("Error in module " ++ show name) Nothing `combineErrors`) $- Module name <$> desugarTypeDeclarations ds <*> pure exps+desugarTypeDeclarationsModule :: (Functor m, Applicative m, MonadError MultipleErrors m) => [Module] -> m [Module]+desugarTypeDeclarationsModule ms = forM ms $ \(Module coms name ds exps) ->+ rethrow (onErrorMessages (ErrorInModule name)) $+ Module coms name <$> desugarTypeDeclarations ds <*> pure exps -- | -- Replace all top level type declarations with type annotations ---desugarTypeDeclarations :: [Declaration] -> Either ErrorStack [Declaration]+desugarTypeDeclarations :: (Functor m, Applicative m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration] desugarTypeDeclarations (PositionedDeclaration pos com d : ds) = do (d' : ds') <- rethrowWithPosition pos $ desugarTypeDeclarations (d : ds) return (PositionedDeclaration pos com d' : ds')@@ -48,13 +51,13 @@ (_, nameKind, val) <- fromValueDeclaration d desugarTypeDeclarations (ValueDeclaration name nameKind [] (Right (TypedValue True val ty)) : rest) where- fromValueDeclaration :: Declaration -> Either ErrorStack (Ident, NameKind, Expr)+ fromValueDeclaration :: (Functor m, Applicative m, MonadError MultipleErrors m) => Declaration -> m (Ident, NameKind, Expr) fromValueDeclaration (ValueDeclaration name' nameKind [] (Right val)) | name == name' = return (name', nameKind, val) fromValueDeclaration (PositionedDeclaration pos com d') = do (ident, nameKind, val) <- rethrowWithPosition pos $ fromValueDeclaration d' return (ident, nameKind, PositionedValue pos com val)- fromValueDeclaration _ = throwError $ mkErrorStack ("Orphan type declaration for " ++ show name) Nothing-desugarTypeDeclarations (TypeDeclaration name _ : []) = throwError $ mkErrorStack ("Orphan type declaration for " ++ show name) Nothing+ fromValueDeclaration _ = throwError . errorMessage $ OrphanTypeDeclaration name+desugarTypeDeclarations (TypeDeclaration name _ : []) = throwError . errorMessage $ OrphanTypeDeclaration name desugarTypeDeclarations (ValueDeclaration name nameKind bs val : rest) = do let (_, f, _) = everywhereOnValuesTopDownM return go return f' (Left gs) = Left <$> mapM (pairM return f) gs
− src/Language/PureScript/Supply.hs
@@ -1,56 +0,0 @@------------------------------------------------------------------------------------ Module : Language.PureScript.Supply--- Copyright : (c) Phil Freeman 2014--- License : MIT------ Maintainer : Phil Freeman <paf31@cantab.net>--- Stability : experimental--- Portability :------ |--- Fresh variable supply-----------------------------------------------------------------------------------{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}--module Language.PureScript.Supply where--import Data.Functor.Identity--import Control.Applicative-import Control.Monad.State-import Control.Monad.Except--newtype SupplyT m a = SupplyT { unSupplyT :: StateT Integer m a } deriving (Functor, Applicative, Monad, MonadTrans)--runSupplyT :: Integer -> SupplyT m a -> m (a, Integer)-runSupplyT n = flip runStateT n . unSupplyT--evalSupplyT :: (Functor m) => Integer -> SupplyT m a -> m a-evalSupplyT n = fmap fst . runSupplyT n--type Supply = SupplyT Identity--runSupply :: Integer -> Supply a -> (a, Integer)-runSupply n = runIdentity . runSupplyT n--evalSupply :: Integer -> Supply a -> a-evalSupply n = runIdentity . evalSupplyT n--fresh :: (Monad m) => SupplyT m Integer-fresh = SupplyT $ do- n <- get- put (n + 1)- return n--freshName :: (Functor m, Monad m) => SupplyT m String-freshName = ('_' :) . show <$> fresh--instance (MonadError e m) => MonadError e (SupplyT m) where- throwError = SupplyT . throwError- catchError e f = SupplyT $ catchError (unSupplyT e) (unSupplyT . f)
src/Language/PureScript/TypeChecker.hs view
@@ -26,8 +26,9 @@ import Language.PureScript.TypeChecker.Synonyms as T import Data.Maybe-import Data.List (nub, (\\), find, intercalate)+import Data.List (nub, (\\)) import Data.Foldable (for_)+ import qualified Data.Map as M import Control.Monad.State@@ -46,7 +47,7 @@ env <- getEnv putEnv $ env { types = M.insert (Qualified (Just moduleName) name) (ctorKind, DataType args dctors) (types env) } forM_ dctors $ \(dctor, tys) ->- rethrow (mkCompileError ("Error in data constructor " ++ show dctor) Nothing `combineErrors`) $+ rethrow (onErrorMessages (ErrorInDataConstructor dctor)) $ addDataConstructor moduleName dtype name (map fst args) dctor tys addDataConstructor :: ModuleName -> DataDeclType -> ProperName -> [String] -> ProperName -> [Type] -> Check ()@@ -70,7 +71,7 @@ valueIsNotDefined moduleName name = do env <- getEnv case M.lookup (moduleName, name) (names env) of- Just _ -> throwError . strMsg $ show name ++ " is already defined"+ Just _ -> throwError . errorMessage $ RedefinedIdent name Nothing -> return () addValue :: ModuleName -> Ident -> Type -> NameKind -> Check ()@@ -94,7 +95,7 @@ checkDuplicateTypeArguments :: [String] -> Check () checkDuplicateTypeArguments args = for_ firstDup $ \dup ->- throwError . strMsg $ "Duplicate type argument '" ++ dup ++ "'"+ throwError . errorMessage $ DuplicateTypeArgument dup where firstDup :: Maybe String firstDup = listToMaybe $ args \\ nub args@@ -103,10 +104,10 @@ checkTypeClassInstance _ (TypeVar _) = return () checkTypeClassInstance _ (TypeConstructor ctor) = do env <- getEnv- when (ctor `M.member` typeSynonyms env) . throwError . strMsg $ "Type synonym instances are disallowed"+ when (ctor `M.member` typeSynonyms env) . throwError . errorMessage $ TypeSynonymInstance return () checkTypeClassInstance m (TypeApp t1 t2) = checkTypeClassInstance m t1 >> checkTypeClassInstance m t2-checkTypeClassInstance _ ty = throwError $ mkErrorStack "Type class instance head is invalid." (Just (TypeError ty))+checkTypeClassInstance _ ty = throwError . errorMessage $ InvalidInstanceHead ty -- | -- Check that type synonyms are fully-applied in a type@@ -133,7 +134,7 @@ go :: [Declaration] -> Check [Declaration] go [] = return [] go (DataDeclaration dtype name args dctors : rest) = do- rethrow (mkCompileError ("Error in type constructor " ++ show name) Nothing `combineErrors`) $ do+ rethrow (onErrorMessages (ErrorInTypeConstructor name)) $ do when (dtype == Newtype) $ checkNewtype dctors checkDuplicateTypeArguments $ map fst args ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)@@ -144,10 +145,10 @@ where checkNewtype :: [(ProperName, [Type])] -> Check () checkNewtype [(_, [_])] = return ()- checkNewtype [(_, _)] = throwError . strMsg $ "newtypes constructors must have a single argument"- checkNewtype _ = throwError . strMsg $ "newtypes must have a single constructor"+ checkNewtype [(_, _)] = throwError . errorMessage $ InvalidNewtype+ checkNewtype _ = throwError . errorMessage $ InvalidNewtype go (d@(DataBindingGroupDeclaration tys) : rest) = do- rethrow (mkCompileError "Error in data binding group" Nothing `combineErrors`) $ do+ rethrow (onErrorMessages ErrorInDataBindingGroup) $ do let syns = mapMaybe toTypeSynonym tys let dataDecls = mapMaybe toDataDecl tys (syn_ks, data_ks) <- kindsOfAll moduleName syns (map (\(_, name, args, dctors) -> (name, args, concatMap snd dctors)) dataDecls)@@ -169,7 +170,7 @@ toDataDecl (PositionedDeclaration _ _ d') = toDataDecl d' toDataDecl _ = Nothing go (TypeSynonymDeclaration name args ty : rest) = do- rethrow (mkCompileError ("Error in type synonym " ++ show name) Nothing `combineErrors`) $ do+ rethrow (onErrorMessages (ErrorInTypeSynonym name)) $ do checkDuplicateTypeArguments $ map fst args kind <- kindsOf False moduleName name args [ty] let args' = args `withKinds` kind@@ -178,7 +179,7 @@ return $ TypeSynonymDeclaration name args ty : ds go (TypeDeclaration _ _ : _) = error "Type declarations should have been removed" go (ValueDeclaration name nameKind [] (Right val) : rest) = do- d <- rethrow (mkCompileError ("Error in declaration " ++ show name) Nothing `combineErrors`) $ do+ d <- rethrow (onErrorMessages (ErrorInValueDeclaration name)) $ do valueIsNotDefined moduleName name [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)] addValue moduleName name ty nameKind@@ -187,7 +188,7 @@ return $ d : ds go (ValueDeclaration{} : _) = error "Binders were not desugared" go (BindingGroupDeclaration vals : rest) = do- d <- rethrow (mkCompileError ("Error in binding group " ++ show (map (\(ident, _, _) -> ident) vals)) Nothing `combineErrors`) $ do+ d <- rethrow (onErrorMessages (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do forM_ (map (\(ident, _, _) -> ident) vals) $ \name -> valueIsNotDefined moduleName name tys <- typesOf mainModuleName moduleName $ map (\(ident, _, ty) -> (ident, ty)) vals@@ -207,19 +208,19 @@ ds <- go rest return $ d : ds go (d@(ExternDeclaration importTy name _ ty) : rest) = do- rethrow (mkCompileError ("Error in foreign import declaration " ++ show name) Nothing `combineErrors`) $ do+ rethrow (onErrorMessages (ErrorInForeignImport name)) $ do env <- getEnv kind <- kindOf moduleName ty- guardWith (strMsg "Expected kind *") $ kind == Star+ guardWith (errorMessage (ExpectedType kind)) $ kind == Star case M.lookup (moduleName, name) (names env) of- Just _ -> throwError . strMsg $ show name ++ " is already defined"+ Just _ -> throwError . errorMessage $ RedefinedIdent name Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, Extern importTy, Defined) (names env) }) ds <- go rest return $ d : ds go (d@(FixityDeclaration _ name) : rest) = do ds <- go rest env <- getEnv- guardWith (strMsg ("Fixity declaration with no binding: " ++ name)) $ M.member (moduleName, Op name) $ names env+ guardWith (errorMessage (OrphanFixityDeclaration name)) $ M.member (moduleName, Op name) $ names env return $ d : ds go (d@(ImportDeclaration importedModule _ _) : rest) = do tcds <- getTypeClassDictionaries@@ -276,74 +277,65 @@ -- required by exported members are also exported. -- typeCheckModule :: Maybe ModuleName -> Module -> Check Module-typeCheckModule _ (Module _ _ Nothing) = error "exports should have been elaborated"-typeCheckModule mainModuleName (Module mn decls (Just exps)) = do+typeCheckModule _ (Module _ _ _ Nothing) = error "exports should have been elaborated"+typeCheckModule mainModuleName (Module coms mn decls (Just exps)) = rethrow (onErrorMessages (ErrorInModule mn)) $ do modify (\s -> s { checkCurrentModule = Just mn }) decls' <- typeCheckAll mainModuleName mn exps decls forM_ exps $ \e -> do checkTypesAreExported e checkClassMembersAreExported e checkClassesAreExported e- return $ Module mn decls' (Just exps)+ return $ Module coms mn decls' (Just exps) where - checkMemberExport :: (Show a) => String -> (Type -> [a]) -> (a -> Bool) -> DeclarationRef -> Check ()- checkMemberExport thing extract test (ValueRef name) = do+ checkMemberExport :: (Type -> [DeclarationRef]) -> DeclarationRef -> Check ()+ checkMemberExport extract dr@(ValueRef name) = do ty <- lookupVariable mn (Qualified (Just mn) name)- case find test (extract ty) of- Just hiddenType -> throwError . strMsg $- "Error in module '" ++ show mn ++ "':\n\- \Exporting declaration '" ++ show name ++ "' requires " ++ thing ++ " '" ++ show hiddenType ++ "' to be exported as well"- Nothing -> return ()- checkMemberExport _ _ _ _ = return ()+ case filter (not . exported) (extract ty) of+ [] -> return ()+ hidden -> throwError . errorMessage $ TransitiveExportError dr hidden+ where+ exported e = any (exports e) exps+ exports (TypeRef pn1 _) (TypeRef pn2 _) = pn1 == pn2+ exports (ValueRef id1) (ValueRef id2) = id1 == id2+ exports (TypeClassRef pn1) (TypeClassRef pn2) = pn1 == pn2+ exports (TypeInstanceRef id1) (TypeInstanceRef id2) = id1 == id2+ exports (PositionedDeclarationRef _ _ r1) r2 = exports r1 r2+ exports r1 (PositionedDeclarationRef _ _ r2) = exports r1 r2+ exports _ _ = False+ checkMemberExport _ _ = return () -- 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 = checkMemberExport "type" findTcons isTconHidden+ checkTypesAreExported = checkMemberExport findTcons where- findTcons :: Type -> [ProperName]+ findTcons :: Type -> [DeclarationRef] findTcons = everythingOnTypes (++) go where- go (TypeConstructor (Qualified (Just mn') name)) | mn' == mn = [name]+ go (TypeConstructor (Qualified (Just mn') name)) | mn' == mn = [TypeRef name (error "Data constructors unused in checkTypesAreExported")] go _ = []- isTconHidden :: ProperName -> Bool- isTconHidden tyName = all go exps- where- go (TypeRef tyName' _) = tyName' /= tyName- go _ = True -- Check that all the classes defined in the current module that appear in member types have also -- been exported from the module checkClassesAreExported :: DeclarationRef -> Check ()- checkClassesAreExported = checkMemberExport "class" findClasses isClassHidden+ checkClassesAreExported = checkMemberExport findClasses where- findClasses :: Type -> [ProperName]+ findClasses :: Type -> [DeclarationRef] findClasses = everythingOnTypes (++) go where- go (ConstrainedType cs _) = mapMaybe (extractCurrentModuleClass . fst) cs+ go (ConstrainedType cs _) = mapMaybe (fmap TypeClassRef . extractCurrentModuleClass . fst) cs go _ = [] extractCurrentModuleClass :: Qualified ProperName -> Maybe ProperName extractCurrentModuleClass (Qualified (Just mn') name) | mn == mn' = Just name extractCurrentModuleClass _ = Nothing- isClassHidden :: ProperName -> Bool- isClassHidden clsName = all go exps- where- go (TypeClassRef clsName') = clsName' /= clsName- go _ = True checkClassMembersAreExported :: DeclarationRef -> Check ()- checkClassMembersAreExported (TypeClassRef name) = do+ checkClassMembersAreExported dr@(TypeClassRef name) = do let members = ValueRef `map` head (mapMaybe findClassMembers decls) let missingMembers = members \\ exps- unless (null missingMembers) $- throwError . strMsg $- "Error in module '" ++ show mn ++ "':\n\- \Class '" ++ show name ++ "' is exported but is missing member exports for '" ++ intercalate "', '" (map (show . runValueRef) missingMembers) ++ "'"+ unless (null missingMembers) $ throwError . errorMessage $ TransitiveExportError dr members where- runValueRef :: DeclarationRef -> Ident- runValueRef (ValueRef refName) = refName- runValueRef _ = error "non-ValueRef passed to runValueRef" findClassMembers :: Declaration -> Maybe [Ident] findClassMembers (TypeClassDeclaration name' _ _ ds) | name == name' = Just $ map extractMemberName ds findClassMembers (PositionedDeclaration _ _ d) = findClassMembers d
src/Language/PureScript/TypeChecker/Entailment.hs view
@@ -31,7 +31,6 @@ import Language.PureScript.Errors import Language.PureScript.Environment import Language.PureScript.Names-import Language.PureScript.Pretty import Language.PureScript.TypeChecker.Monad import Language.PureScript.TypeChecker.Synonyms import Language.PureScript.TypeChecker.Unify@@ -40,29 +39,6 @@ import qualified Language.PureScript.Constants as C -- |--- A simplified representation of expressions which are used to represent type--- class dictionaries at runtime, which can be compared for equality----data DictionaryValue- -- |- -- A dictionary which is brought into scope by a local constraint- --- = LocalDictionaryValue (Qualified Ident)- -- |- -- A dictionary which is brought into scope by an instance declaration- --- | GlobalDictionaryValue (Qualified Ident)- -- |- -- A dictionary which depends on other dictionaries- --- | DependentDictionaryValue (Qualified Ident) [DictionaryValue]- -- |- -- A subclass dictionary- --- | SubclassDictionaryValue DictionaryValue (Qualified ProperName) Integer- deriving (Show, Ord, Eq)---- | -- Check that the current set of type class dictionaries entail the specified type class goal, and, if so, -- return a type class dictionary reference. --@@ -140,16 +116,9 @@ checkOverlaps :: [DictionaryValue] -> Check Expr checkOverlaps dicts = case [ (d1, d2) | d1 <- dicts, d2 <- dicts, d1 `overlapping` d2 ] of- (d1, d2) : _ -> throwError . strMsg $ unlines- [ "Overlapping instances found for " ++ show className ++ " " ++ unwords (map prettyPrintType tys) ++ "."- , "For example:"- , prettyPrintDictionaryValue d1- , "and:"- , prettyPrintDictionaryValue d2- ]+ ds@(_ : _) -> throwError . errorMessage $ OverlappingInstances className tys (map fst ds) _ -> case chooseSimplestDictionaries dicts of- [] -> throwError . strMsg $- "No instance found for " ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)+ [] -> throwError . errorMessage $ NoInstanceFound className tys d : _ -> return $ dictionaryValueToValue d -- Choose the simplest DictionaryValues from a list of candidates -- The reason for this function is as follows:@@ -180,18 +149,6 @@ overlapping SubclassDictionaryValue{} _ = False overlapping _ SubclassDictionaryValue{} = False overlapping _ _ = True- -- |- -- Render a DictionaryValue fit for human consumption in error messages- --- prettyPrintDictionaryValue :: DictionaryValue -> String- prettyPrintDictionaryValue = unlines . indented 0- where- indented n (LocalDictionaryValue _) = [spaces n ++ "Dictionary in scope"]- indented n (GlobalDictionaryValue nm) = [spaces n ++ show nm]- indented n (DependentDictionaryValue nm args) = (spaces n ++ show nm ++ " via") : concatMap (indented (n + 2)) args- indented n (SubclassDictionaryValue sup nm _) = (spaces n ++ show nm ++ " via superclass") : indented (n + 2) sup-- spaces n = replicate n ' ' ++ "- " valUndefined :: Expr valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
src/Language/PureScript/TypeChecker/Kinds.hs view
@@ -38,7 +38,6 @@ import Language.PureScript.Errors import Language.PureScript.Kinds import Language.PureScript.Names-import Language.PureScript.Pretty import Language.PureScript.TypeChecker.Monad import Language.PureScript.Types @@ -65,7 +64,7 @@ FunKind k1 k2 =?= FunKind k3 k4 = do k1 =?= k3 k2 =?= k4- k1 =?= k2 = UnifyT . lift . throwError . strMsg $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."+ k1 =?= k2 = UnifyT . lift . throwError . errorMessage $ KindsDoNotUnify k1 k2 -- | -- Infer the kind of a single type@@ -78,7 +77,7 @@ -- kindOfWithScopedVars :: Type -> Check (Kind, [(String, Kind)]) kindOfWithScopedVars ty = - rethrow (mkCompileError "Error checking kind" (Just (TypeError ty)) `combineErrors`) $+ rethrow (onErrorMessages (ErrorCheckingKind ty)) $ fmap tidyUp . liftUnify $ infer ty where tidyUp ((k, args), sub) = ( starIfUnknown (sub $? k)@@ -156,7 +155,7 @@ -- Infer a kind for a type -- infer :: Type -> UnifyT Kind Check (Kind, [(String, Kind)])-infer ty = rethrow (mkCompileError "Error inferring type of value" (Just (TypeError ty)) `combineErrors`) $ infer' ty+infer ty = rethrow (onErrorMessages (ErrorCheckingKind ty)) $ infer' ty infer' :: Type -> UnifyT Kind Check (Kind, [(String, Kind)]) infer' (ForAll ident ty _) = do@@ -189,10 +188,10 @@ go (Skolem v _ _) = do Just moduleName <- checkCurrentModule <$> get UnifyT . lift $ lookupTypeVariable moduleName (Qualified Nothing (ProperName v))- go c@(TypeConstructor v) = do+ go (TypeConstructor v) = do env <- liftCheck getEnv case M.lookup v (types env) of- Nothing -> UnifyT . lift . throwError $ mkErrorStack "Unknown type constructor" (Just (TypeError c))+ Nothing -> UnifyT . lift . throwError . errorMessage $ UnknownTypeConstructor v Just (kind, _) -> return kind go (TypeApp t1 t2) = do k0 <- fresh
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -109,41 +109,41 @@ -- | -- Lookup the type of a value by name in the @Environment@ ---lookupVariable :: (e ~ ErrorStack, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m Type+lookupVariable :: (e ~ MultipleErrors, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m Type lookupVariable currentModule (Qualified moduleName var) = do env <- getEnv case M.lookup (fromMaybe currentModule moduleName, var) (names env) of- Nothing -> throwError . strMsg $ show var ++ " is undefined"+ Nothing -> throwError . errorMessage $ NameIsUndefined var Just (ty, _, _) -> return ty -- | -- Lookup the visibility of a value by name in the @Environment@ ---getVisibility :: (e ~ ErrorStack, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m NameVisibility+getVisibility :: (e ~ MultipleErrors, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m NameVisibility getVisibility currentModule (Qualified moduleName var) = do env <- getEnv case M.lookup (fromMaybe currentModule moduleName, var) (names env) of- Nothing -> throwError . strMsg $ show var ++ " is undefined"+ Nothing -> throwError . errorMessage $ NameIsUndefined var Just (_, _, vis) -> return vis -- | -- Assert that a name is visible ---checkVisibility :: (e ~ ErrorStack, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m ()+checkVisibility :: (e ~ MultipleErrors, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified Ident -> m () checkVisibility currentModule name@(Qualified _ var) = do vis <- getVisibility currentModule name case vis of- Undefined -> throwError . strMsg $ show var ++ " may not be defined in the current scope."+ Undefined -> throwError . errorMessage $ NameNotInScope var _ -> return () -- | -- Lookup the kind of a type by name in the @Environment@ ---lookupTypeVariable :: (e ~ ErrorStack, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified ProperName -> m Kind+lookupTypeVariable :: (e ~ MultipleErrors, Functor m, MonadState CheckState m, MonadError e m) => ModuleName -> Qualified ProperName -> m Kind lookupTypeVariable currentModule (Qualified moduleName name) = do env <- getEnv case M.lookup (Qualified (Just $ fromMaybe currentModule moduleName) name) (types env) of- Nothing -> throwError . strMsg $ "Type variable " ++ show name ++ " is undefined"+ Nothing -> throwError . errorMessage $ UndefinedTypeVariable name Just (k, _) -> return k -- |@@ -171,8 +171,8 @@ -- | -- The type checking monad, which provides the state of the type checker, and error reporting capabilities ---newtype Check a = Check { unCheck :: StateT CheckState (Either ErrorStack) a }- deriving (Functor, Monad, Applicative, MonadState CheckState, MonadError ErrorStack)+newtype Check a = Check { unCheck :: StateT CheckState (Either MultipleErrors) a }+ deriving (Functor, Monad, Applicative, MonadState CheckState, MonadError MultipleErrors) -- | -- Get the current @Environment@@@ -204,9 +204,9 @@ runCheck' :: (MonadReader (Options mode) m, MonadError String m) => Environment -> Check a -> m (a, Environment) runCheck' env c = do verbose <- asks optionsVerboseErrors- stringifyErrorStack verbose $ do- (a, s) <- flip runStateT (CheckState env 0 0 Nothing) $ unCheck c- return (a, checkEnv s)+ interpretMultipleErrors verbose $ do+ (a, s) <- flip runStateT (CheckState env 0 0 Nothing) $ unCheck c+ return (a, checkEnv s) -- | -- Make an assertion, failing with an error message
src/Language/PureScript/TypeChecker/Rows.hs view
@@ -53,7 +53,7 @@ checkDups r@RCons{} = let (ls, _) = rowToList r in case firstDup . sort . map fst $ ls of- Just l -> throwError $ mkErrorStack ("Duplicate label " ++ show l ++ " in row") $ Just (ExprError val)+ Just l -> throwError . errorMessage $ DuplicateLabel l (Just val) Nothing -> return () checkDups _ = return ()
src/Language/PureScript/TypeChecker/Skolems.hs view
@@ -31,7 +31,6 @@ import Language.PureScript.AST import Language.PureScript.Errors-import Language.PureScript.Pretty import Language.PureScript.TypeChecker.Monad import Language.PureScript.Types @@ -89,7 +88,7 @@ let (_, f, _, _, _) = everythingWithContextOnValues [] [] (++) def go def def def in case f root of [] -> return ()- ((binding, val) : _) -> throwError $ mkErrorStack ("Rigid/skolem type variable " ++ maybe "" (("bound by " ++) . prettyPrintValue) binding ++ " has escaped.") (Just (ExprError val))+ ((binding, val) : _) -> throwError . errorMessage . ErrorInExpression val $ EscapedSkolem binding where def s _ = (s, []) @@ -112,4 +111,4 @@ where go' val@(TypedValue _ _ (ForAll _ _ (Just sco'))) | sco == sco' = First (Just val) go' _ = mempty-skolemEscapeCheck val = throwError $ mkErrorStack "Untyped value passed to skolemEscapeCheck" (Just (ExprError val))+skolemEscapeCheck _ = error "Untyped value passed to skolemEscapeCheck"
src/Language/PureScript/TypeChecker/Subsumption.hs view
@@ -20,14 +20,12 @@ import Data.List (sortBy) import Data.Ord (comparing) -import Control.Applicative import Control.Monad.Except import Control.Monad.Unify import Language.PureScript.AST import Language.PureScript.Environment import Language.PureScript.Errors-import Language.PureScript.Pretty import Language.PureScript.TypeChecker.Monad import Language.PureScript.TypeChecker.Skolems import Language.PureScript.TypeChecker.Synonyms@@ -38,12 +36,7 @@ -- Check whether one type subsumes another, rethrowing errors to provide a better error message -- subsumes :: Maybe Expr -> Type -> Type -> UnifyT Type Check (Maybe Expr)-subsumes val ty1 ty2 = rethrow (mkCompileError errorMessage (ExprError <$> val) `combineErrors`) $ subsumes' val ty1 ty2- where- errorMessage = "Error checking that type "- ++ prettyPrintType ty1- ++ " subsumes type "- ++ prettyPrintType ty2+subsumes val ty1 ty2 = rethrow (onErrorMessages (ErrorInSubsumption ty1 ty2)) $ subsumes' val ty1 ty2 -- | -- Check whether one type subsumes another@@ -58,7 +51,7 @@ sko <- newSkolemConstant let sk = skolemize ident sko sco' ty2 subsumes val ty1 sk- Nothing -> throwError . strMsg $ "Skolem variable scope is unspecified"+ Nothing -> throwError . errorMessage $ UnspecifiedSkolemScope subsumes' val (TypeApp (TypeApp f1 arg1) ret1) (TypeApp (TypeApp f2 arg2) ret2) | f1 == tyFunction && f2 == tyFunction = do _ <- subsumes Nothing arg2 arg1 _ <- subsumes Nothing ret1 ret2
src/Language/PureScript/TypeChecker/Synonyms.hs view
@@ -40,19 +40,19 @@ -- | -- Build a type substitution for a type synonym ---buildTypeSubstitution :: Qualified ProperName -> Int -> Type -> Either String (Maybe Type)+buildTypeSubstitution :: Qualified ProperName -> Int -> Type -> Either ErrorMessage (Maybe Type) buildTypeSubstitution name n = go n [] where- go :: Int -> [Type] -> Type -> Either String (Maybe Type)+ go :: Int -> [Type] -> Type -> Either ErrorMessage (Maybe Type) go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)- go m _ (TypeConstructor ctor) | m > 0 && name == ctor = throwError $ "Partially applied type synonym " ++ show name+ go m _ (TypeConstructor ctor) | m > 0 && name == ctor = throwError $ PartiallyAppliedSynonym name go m args (TypeApp f arg) = go (m - 1) (arg:args) f go _ _ _ = return Nothing -- | -- Replace all instances of a specific type synonym with the @SaturatedTypeSynonym@ data constructor ---saturateTypeSynonym :: Qualified ProperName -> Int -> Type -> Either String Type+saturateTypeSynonym :: Qualified ProperName -> Int -> Type -> Either ErrorMessage Type saturateTypeSynonym name n = everywhereOnTypesTopDownM replace where replace t = fromMaybe t <$> buildTypeSubstitution name n t@@ -60,7 +60,7 @@ -- | -- Replace all type synonyms with the @SaturatedTypeSynonym@ data constructor ---saturateAllTypeSynonyms :: [(Qualified ProperName, Int)] -> Type -> Either String Type+saturateAllTypeSynonyms :: [(Qualified ProperName, Int)] -> Type -> Either ErrorMessage Type saturateAllTypeSynonyms syns d = foldM (\result (name, n) -> saturateTypeSynonym name n result) d syns -- |@@ -76,22 +76,22 @@ -- Replace fully applied type synonyms with the @SaturatedTypeSynonym@ data constructor, which helps generate -- better error messages during unification. ---replaceAllTypeSynonyms' :: Environment -> Type -> Either String Type+replaceAllTypeSynonyms' :: Environment -> Type -> Either ErrorMessage Type replaceAllTypeSynonyms' env d = let syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env in saturateAllTypeSynonyms syns d -replaceAllTypeSynonyms :: (e ~ ErrorStack, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Type -> m Type+replaceAllTypeSynonyms :: (e ~ MultipleErrors, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Type -> m Type replaceAllTypeSynonyms d = do env <- getEnv- either (throwError . strMsg) return $ replaceAllTypeSynonyms' env d+ either (throwError . errorMessage) return $ replaceAllTypeSynonyms' env d -- | -- Replace a type synonym and its arguments with the aliased type ---expandTypeSynonym' :: Environment -> Qualified ProperName -> [Type] -> Either String Type+expandTypeSynonym' :: Environment -> Qualified ProperName -> [Type] -> Either ErrorMessage Type expandTypeSynonym' env name args = case M.lookup name (typeSynonyms env) of Just (synArgs, body) -> do@@ -99,12 +99,12 @@ replaceAllTypeSynonyms' env repl Nothing -> error "Type synonym was not defined" -expandTypeSynonym :: (e ~ ErrorStack, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Qualified ProperName -> [Type] -> m Type+expandTypeSynonym :: (e ~ MultipleErrors, Functor m, Monad m, MonadState CheckState m, MonadError e m) => Qualified ProperName -> [Type] -> m Type expandTypeSynonym name args = do env <- getEnv- either (throwError . strMsg) return $ expandTypeSynonym' env name args+ either (throwError . errorMessage) return $ expandTypeSynonym' env name args -expandAllTypeSynonyms :: (e ~ ErrorStack, Functor m, Applicative m, Monad m, MonadState CheckState m, MonadError e m) => Type -> m Type+expandAllTypeSynonyms :: (e ~ MultipleErrors, Functor m, Applicative m, Monad m, MonadState CheckState m, MonadError e m) => Type -> m Type expandAllTypeSynonyms = everywhereOnTypesTopDownM go where go (SaturatedTypeSynonym name args) = expandTypeSynonym name args
src/Language/PureScript/TypeChecker/Types.hs view
@@ -39,7 +39,6 @@ import Data.List import Data.Maybe (fromMaybe) import qualified Data.Map as M-import Data.String (IsString) import Control.Applicative import Control.Monad.Except@@ -51,7 +50,6 @@ import Language.PureScript.Errors import Language.PureScript.Kinds import Language.PureScript.Names-import Language.PureScript.Pretty import Language.PureScript.Traversals import Language.PureScript.TypeChecker.Entailment import Language.PureScript.TypeChecker.Kinds@@ -184,7 +182,7 @@ -- Check the kind of a type, failing if it is not of kind *. -- checkTypeKind :: Kind -> UnifyT t Check ()-checkTypeKind kind = guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star+checkTypeKind kind = guardWith (errorMessage (ExpectedType kind)) $ kind == Star -- | -- Remove any ForAlls and ConstrainedType constructors in a type by introducing new unknowns@@ -207,7 +205,7 @@ -- Infer a type for a value, rethrowing any error to provide a more useful error message -- infer :: Expr -> UnifyT Type Check Expr-infer val = rethrow (mkCompileError "Error inferring type of value" (Just (ExprError val)) `combineErrors`) $ infer' val+infer val = rethrow (onErrorMessages (ErrorInferringType val)) $ infer' val -- | -- Infer a type for a value@@ -269,7 +267,7 @@ infer' v@(Constructor c) = do env <- getEnv case M.lookup c (dataConstructors env) of- Nothing -> throwError . strMsg $ "Constructor " ++ show c ++ " is undefined"+ Nothing -> throwError . errorMessage $ UnknownDataConstructor c Nothing Just (_, _, ty, _) -> do (v', ty') <- sndM (introduceSkolemScope <=< replaceAllTypeSynonyms) <=< instantiatePolyTypeWithUnknowns v $ ty return $ TypedValue True v' ty' infer' (Case vals binders) = do@@ -365,8 +363,8 @@ return M.empty go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction = M.union <$> inferBinder obj binder <*> go binders' ret- go _ _ = throwError . strMsg $ "Wrong number of arguments to constructor " ++ show ctor- _ -> throwError . strMsg $ "Constructor " ++ show ctor ++ " is not defined"+ go _ _ = throwError . errorMessage $ IncorrectConstructorArity ctor+ _ -> throwError . errorMessage $ UnknownDataConstructor ctor Nothing inferBinder val (ObjectBinder props) = do row <- fresh rest <- fresh@@ -404,7 +402,7 @@ checkBinders :: [Type] -> Type -> [CaseAlternative] -> UnifyT Type Check [CaseAlternative] checkBinders _ _ [] = return [] checkBinders nvals ret (CaseAlternative binders result : bs) = do- guardWith (strMsg "Overlapping binders in case statement") $+ guardWith (errorMessage $ OverlappingArgNames Nothing) $ let ns = concatMap binderNames binders in length (nub ns) == length ns Just moduleName <- checkCurrentModule <$> get m1 <- M.unions <$> zipWithM inferBinder nvals binders@@ -427,13 +425,7 @@ -- Check the type of a value, rethrowing errors to provide a better error message -- check :: Expr -> Type -> UnifyT Type Check Expr-check val ty = rethrow (mkCompileError errorMessage (Just (ExprError val)) `combineErrors`) $ check' val ty- where- errorMessage =- "Error checking type of term " ++- prettyPrintValue val ++- " against type " ++- prettyPrintType ty+check val ty = rethrow (onErrorMessages (ErrorCheckingType val ty)) $ check' val ty -- | -- Check the type of a value@@ -490,7 +482,7 @@ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty v' <- subsumes (Just v) repl ty' case v' of- Nothing -> throwError . strMsg $ "Unable to check type subsumption"+ Nothing -> throwError . errorMessage $ SubsumptionCheckFailed Just v'' -> return $ TypedValue True v'' ty' check' (SuperClassDictionary className tys) _ = do {-@@ -513,10 +505,10 @@ ty2' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty2 val' <- subsumes (Just val) ty1' ty2' case val' of- Nothing -> throwError . strMsg $ "Unable to check type subsumption"- Just val'' -> do- val''' <- if checkType then withScopedTypeVars moduleName args (check val'' ty2') else return val''- return $ TypedValue checkType (TypedValue True val''' ty1') ty2'+ Nothing -> throwError . errorMessage $ SubsumptionCheckFailed+ Just _ -> do+ val''' <- if checkType then withScopedTypeVars moduleName args (check val ty2') else return val+ return $ TypedValue checkType val''' ty2' check' (Case vals binders) ret = do vals' <- mapM infer vals let ts = map (\(TypedValue _ _ t) -> t) vals'@@ -551,7 +543,7 @@ check' (Constructor c) ty = do env <- getEnv case M.lookup c (dataConstructors env) of- Nothing -> throwError . strMsg $ "Constructor " ++ show c ++ " is undefined"+ Nothing -> throwError . errorMessage $ UnknownDataConstructor c Nothing Just (_, _, ty1, _) -> do repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1 _ <- subsumes Nothing repl ty@@ -568,7 +560,7 @@ return $ TypedValue True val' kt check' (PositionedValue pos _ val) ty = rethrowWithPosition pos $ check' val ty-check' val ty = throwError $ mkErrorStack ("Expr does not have type " ++ prettyPrintType ty) (Just (ExprError val))+check' val ty = throwError . errorMessage $ ExprDoesNotHaveType val ty containsTypeSynonyms :: Type -> Bool containsTypeSynonyms = everythingOnTypes (||) go where@@ -589,8 +581,8 @@ return [] go [] [] Skolem{} | lax = return [] go [] ((p, _): _) _ | lax = return []- | otherwise = throwError $ mkErrorStack ("Object does not have property " ++ p) (Just (ExprError (ObjectLiteral ps)))- go ((p,_):_) [] REmpty = throwError $ mkErrorStack ("Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row) (Just (ExprError (ObjectLiteral ps)))+ | otherwise = throwError . errorMessage $ PropertyIsMissing p row+ go ((p,_):_) [] REmpty = throwError . errorMessage $ PropertyIsMissing p row go ((p,v):ps') ts r = case lookup p ts of Nothing -> do@@ -603,19 +595,15 @@ v' <- check v ty ps'' <- go ps' (delete (p, ty) ts) r return $ (p, v') : ps''- go _ _ _ = throwError $ mkErrorStack ("Object does not have type " ++ prettyPrintType (TypeApp tyObject row)) (Just (ExprError (ObjectLiteral ps)))+ go _ _ _ = throwError . errorMessage $ ExprDoesNotHaveType (ObjectLiteral ps) (TypeApp tyObject row) -- | -- Check the type of a function application, rethrowing errors to provide a better error message -- checkFunctionApplication :: Expr -> Type -> Expr -> Maybe Type -> UnifyT Type Check (Type, Expr)-checkFunctionApplication fn fnTy arg ret = rethrow (mkCompileError errorMessage (Just (ExprError fn)) `combineErrors`) $ do+checkFunctionApplication fn fnTy arg ret = rethrow (onErrorMessages (ErrorInApplication fn fnTy arg)) $ do subst <- unifyCurrentSubstitution <$> UnifyT get checkFunctionApplication' fn (subst $? fnTy) arg (($?) subst <$> ret)- where- errorMessage = "Error applying function of type "- ++ prettyPrintType fnTy- ++ " to argument " ++ prettyPrintValue arg -- | -- Check the type of a function application@@ -651,9 +639,7 @@ checkFunctionApplication' (foldl App fn (map (flip (TypeClassDictionary True) dicts) constraints)) fnTy arg ret checkFunctionApplication' fn fnTy dict@TypeClassDictionary{} _ = return (fnTy, App fn dict)-checkFunctionApplication' _ fnTy arg _ = throwError . strMsg $ "Cannot apply a function of type "- ++ prettyPrintType fnTy- ++ " to argument " ++ prettyPrintValue arg+checkFunctionApplication' _ fnTy arg _ = throwError . errorMessage $ CannotApplyFunction fnTy arg -- | -- Compute the meet of two types, i.e. the most general type which both types subsume.@@ -673,5 +659,9 @@ -- | -- Ensure a set of property names and value does not contain duplicate labels ---ensureNoDuplicateProperties :: (IsString e, MonadError e m) => [(String, Expr)] -> m ()-ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps+ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(String, Expr)] -> m ()+ensureNoDuplicateProperties ps =+ let ls = map fst ps in+ case ls \\ nub ls of+ l : _ -> throwError . errorMessage $ DuplicateLabel l Nothing+ _ -> return ()
src/Language/PureScript/TypeChecker/Unify.hs view
@@ -34,7 +34,6 @@ import Language.PureScript.Environment import Language.PureScript.Errors-import Language.PureScript.Pretty import Language.PureScript.TypeChecker.Monad import Language.PureScript.TypeChecker.Skolems import Language.PureScript.TypeChecker.Synonyms@@ -60,7 +59,7 @@ -- Unify two types, updating the current substitution -- unifyTypes :: Type -> Type -> UnifyT Type Check ()-unifyTypes t1 t2 = rethrow (mkCompileError ("Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2) Nothing `combineErrors`) $+unifyTypes t1 t2 = rethrow (onErrorMessages (ErrorUnifyingTypes t1 t2)) $ unifyTypes' t1 t2 where unifyTypes' (TUnknown u1) (TUnknown u2) | u1 == u2 = return ()@@ -82,11 +81,11 @@ sko <- newSkolemConstant let sk = skolemize ident sko sc ty1 sk `unifyTypes` ty2- unifyTypes' ForAll{} _ = throwError . strMsg $ "Skolem variable scope is unspecified"+ unifyTypes' ForAll{} _ = throwError . errorMessage $ UnspecifiedSkolemScope unifyTypes' ty f@ForAll{} = f `unifyTypes` ty unifyTypes' (TypeVar v1) (TypeVar v2) | v1 == v2 = return ()- unifyTypes' (TypeConstructor c1) (TypeConstructor c2) =- guardWith (strMsg ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".")) (c1 == c2)+ unifyTypes' ty1@(TypeConstructor c1) ty2@(TypeConstructor c2) =+ guardWith (errorMessage (TypesDoNotUnify ty1 ty2)) (c1 == c2) unifyTypes' (TypeApp t3 t4) (TypeApp t5 t6) = do t3 `unifyTypes` t5 t4 `unifyTypes` t6@@ -97,9 +96,9 @@ unifyTypes' r1 r2@RCons{} = unifyRows r1 r2 unifyTypes' r1@REmpty r2 = unifyRows r1 r2 unifyTypes' r1 r2@REmpty = unifyRows r1 r2- unifyTypes' t@(ConstrainedType _ _) _ = throwError . strMsg $ "Attempted to unify a constrained type " ++ prettyPrintType t ++ " with another type."+ unifyTypes' ty1@(ConstrainedType _ _) ty2 = throwError . errorMessage $ ConstrainedTypeUnified ty1 ty2 unifyTypes' t3 t4@(ConstrainedType _ _) = unifyTypes' t4 t3- unifyTypes' t3 t4 = throwError . strMsg $ "Cannot unify " ++ prettyPrintType t3 ++ " with " ++ prettyPrintType t4 ++ "."+ unifyTypes' t3 t4 = throwError . errorMessage $ TypesDoNotUnify t3 t4 -- | -- Unify two rows, updating the current substitution@@ -136,7 +135,7 @@ unifyRows' [] REmpty [] REmpty = return () unifyRows' [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = return () unifyRows' [] (Skolem _ s1 _) [] (Skolem _ s2 _) | s1 == s2 = return ()- unifyRows' sd3 r3 sd4 r4 = throwError . strMsg $ "Cannot unify (" ++ prettyPrintRow (rowFromList (sd3, r3)) ++ ") with (" ++ prettyPrintRow (rowFromList (sd4, r4)) ++ ")"+ unifyRows' sd3 r3 sd4 r4 = throwError . errorMessage $ TypesDoNotUnify (rowFromList (sd3, r3)) (rowFromList (sd4, r4)) -- | -- Check that two types unify
src/Language/PureScript/TypeClassDictionaries.hs view
@@ -66,6 +66,29 @@ | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable) -- |+-- A simplified representation of expressions which are used to represent type+-- class dictionaries at runtime, which can be compared for equality+--+data DictionaryValue+ -- |+ -- A dictionary which is brought into scope by a local constraint+ --+ = LocalDictionaryValue (Qualified Ident)+ -- |+ -- A dictionary which is brought into scope by an instance declaration+ --+ | GlobalDictionaryValue (Qualified Ident)+ -- |+ -- A dictionary which depends on other dictionaries+ --+ | DependentDictionaryValue (Qualified Ident) [DictionaryValue]+ -- |+ -- A subclass dictionary+ --+ | SubclassDictionaryValue DictionaryValue (Qualified ProperName) Integer+ deriving (Show, Ord, Eq)++-- | -- Find the original dictionary which a type class dictionary in scope refers to -- canonicalizeDictionary :: TypeClassDictionaryInScope -> Qualified Ident
tests/Main.hs view
@@ -77,7 +77,7 @@ putStrLn $ "Assert " ++ inputFile ++ " does not compile" assert preludeExterns (P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] }) inputFile $ \e -> case e of- Left _ -> return Nothing+ Left err -> putStrLn err >> return Nothing Right _ -> return $ Just "Should not have compiled" findNodeProcess :: IO (Maybe String)