packages feed

purescript 0.6.9.3 → 0.6.9.4

raw patch · 44 files changed

+2386/−1518 lines, 44 filesdep +HUnitdep ~basedep ~directorydep ~mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: HUnit

Dependency ranges changed: base, directory, mtl, transformers

API changes (from Hackage documentation)

- Language.PureScript.Constants: bitsNumber :: String
- Language.PureScript.Constants: boolLikeBoolean :: String
- Language.PureScript.Constants: numNumber :: String
+ Language.PureScript.AST.SourcePos: displaySourcePos :: SourcePos -> String
+ Language.PureScript.AST.SourcePos: displaySourceSpan :: SourceSpan -> String
+ Language.PureScript.Constants: bottom :: String
+ Language.PureScript.Constants: boundedBoolean :: String
+ Language.PureScript.Constants: complementedLatticeBoolean :: String
+ Language.PureScript.Constants: dataInt :: String
+ Language.PureScript.Constants: dataIntBits :: String
+ Language.PureScript.Constants: eqInt :: String
+ Language.PureScript.Constants: fromNumber :: String
+ Language.PureScript.Constants: inf :: String
+ Language.PureScript.Constants: latticeBoolean :: String
+ Language.PureScript.Constants: mod :: String
+ Language.PureScript.Constants: moduloSemiringInt :: String
+ Language.PureScript.Constants: ordInt :: String
+ Language.PureScript.Constants: ringInt :: String
+ Language.PureScript.Constants: semiringInt :: String
+ Language.PureScript.Constants: sup :: String
+ Language.PureScript.Constants: top :: String
+ Language.PureScript.Errors: CannotGetFileInfo :: FilePath -> ErrorMessage
+ Language.PureScript.Errors: CannotReadFile :: FilePath -> ErrorMessage
+ Language.PureScript.Errors: CannotWriteFile :: FilePath -> ErrorMessage
+ Language.PureScript.Errors: CycleInModules :: [ModuleName] -> ErrorMessage
+ Language.PureScript.Errors: ErrorParsingExterns :: ParseError -> ErrorMessage
+ Language.PureScript.Errors: ErrorParsingPrelude :: ParseError -> ErrorMessage
+ Language.PureScript.Errors: InvalidExternsFile :: FilePath -> ErrorMessage
+ Language.PureScript.TypeChecker.Monad: preservingNames :: (Functor m, MonadState CheckState m) => m a -> m a
+ Language.PureScript.TypeChecker.Monad: withBindingGroupVisible :: (Functor m, MonadState CheckState m) => m a -> m a
- Language.PureScript: class (MonadReader (Options Make) m, MonadError String m) => MonadMake m
+ Language.PureScript: class (MonadReader (Options Make) m, MonadError MultipleErrors m) => MonadMake m
- Language.PureScript: compile :: (Functor m, Applicative m, MonadError String m, MonadReader (Options Compile) m) => [Module] -> [String] -> m (String, String, Environment)
+ Language.PureScript: compile :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadReader (Options Compile) m) => [Module] -> [String] -> m (String, String, Environment)
- Language.PureScript: compile' :: (Functor m, Applicative m, MonadError String m, MonadReader (Options Compile) m) => Environment -> [Module] -> [String] -> m (String, String, Environment)
+ Language.PureScript: compile' :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadReader (Options Compile) m) => Environment -> [Module] -> [String] -> m (String, String, Environment)
- Language.PureScript.AST.Declarations: exportedDctors :: Module -> ProperName -> [ProperName]
+ Language.PureScript.AST.Declarations: exportedDctors :: Module -> ProperName -> [(ProperName, [Type])]
- Language.PureScript.Errors: interpretMultipleErrors :: MonadError String m => Bool -> Either MultipleErrors a -> m a
+ Language.PureScript.Errors: interpretMultipleErrors :: MonadError MultipleErrors m => Either MultipleErrors a -> m a
- Language.PureScript.ModuleDependencies: sortModules :: MonadError String m => [Module] -> m ([Module], ModuleGraph)
+ Language.PureScript.ModuleDependencies: sortModules :: MonadError MultipleErrors m => [Module] -> m ([Module], ModuleGraph)
- Language.PureScript.TypeChecker.Monad: makeBindingGroupVisible :: (Functor m, MonadState CheckState m) => m a -> m a
+ Language.PureScript.TypeChecker.Monad: makeBindingGroupVisible :: (Functor m, MonadState CheckState m) => m ()
- Language.PureScript.TypeChecker.Monad: runCheck :: (MonadReader (Options mode) m, MonadError String m) => Check a -> m (a, Environment)
+ Language.PureScript.TypeChecker.Monad: runCheck :: MonadError MultipleErrors m => Check a -> m (a, Environment)
- Language.PureScript.TypeChecker.Monad: runCheck' :: (MonadReader (Options mode) m, MonadError String m) => Environment -> Check a -> m (a, Environment)
+ Language.PureScript.TypeChecker.Monad: runCheck' :: MonadError MultipleErrors m => Environment -> Check a -> m (a, Environment)

Files

+ examples/failing/365.purs view
@@ -0,0 +1,11 @@+module Main where++class C a where+  f :: a -> a+  g :: a -> a++instance cS :: C String where+  f s = s+  g = f++main = g "Done"
+ examples/failing/RowConstructors1.purs view
@@ -0,0 +1,6 @@+module Main where++data Foo = Bar+type Baz = { | Foo }++main = Debug.Trace.trace "Done"
+ examples/failing/RowConstructors2.purs view
@@ -0,0 +1,6 @@+module Main where++type Foo r = (x :: Number | r)+type Bar = { | Foo }++main = Debug.Trace.trace "Done"
+ examples/failing/RowConstructors3.purs view
@@ -0,0 +1,6 @@+module Main where++type Foo = { x :: Number }+type Bar = { | Foo }++main = Debug.Trace.trace "Done"
+ examples/failing/TypeSynonyms5.purs view
@@ -0,0 +1,3 @@+module Main where++type T = T
+ examples/passing/CaseStatement.purs view
@@ -0,0 +1,19 @@+module Main where++data A = A | B | C++f a _ A = a+f _ a B = a+f _ _ C = "Done"++g a _ A = a+g _ b B = b+g _ _ C = C++data M a = N | J a++h f N a = a+h f a N = a+h f (J a) (J b) = J (f a b)++main = Debug.Trace.trace $ f "Done" "Failed" A
examples/passing/Collatz.purs view
@@ -1,8 +1,19 @@ module Main where -import Prelude import Control.Monad.Eff import Control.Monad.ST++foreign import jsMod+  """+  function jsMod(x) {+    return function (y) {+      return x % y;+    };+  }+  """ :: Number -> Number -> Number++infixl 7 %+(%) = jsMod  collatz :: Number -> Number collatz n = runPure (runST (do
examples/passing/Guards.purs view
@@ -1,29 +1,39 @@ module Main where -  import Prelude+foreign import jsMod+  """+  function jsMod(x) {+    return function (y) {+      return x % y;+    };+  }+  """ :: Number -> Number -> Number -  collatz = \x -> case x of-    y | y % 2 == 0 -> y / 2-    y -> y * 3 + 1+infixl 7 %+(%) = jsMod -  -- Guards have access to current scope-  collatz2 = \x y -> case x of-    z | y > 0 -> z / 2-    z -> z * 3 + 1+collatz = \x -> case x of+  y | y % 2 == 0 -> y / 2+  y -> y * 3 + 1 -  min :: forall a. (Ord a) => a -> a -> a-  min n m | n < m     = n-          | otherwise = m+-- Guards have access to current scope+collatz2 = \x y -> case x of+  z | y > 0 -> z / 2+  z -> z * 3 + 1 -  max :: forall a. (Ord a) => a -> a -> a-  max n m = case unit of-    _ | m < n     -> n-      | otherwise -> m+min :: forall a. (Ord a) => a -> a -> a+min n m | n < m     = n+        | otherwise = m -  testIndentation :: Number -> Number -> Number-  testIndentation x y | x > 0-    = x + y-                      | otherwise-    = y - x+max :: forall a. (Ord a) => a -> a -> a+max n m = case unit of+  _ | m < n     -> n+    | otherwise -> m -  main = Debug.Trace.trace $ min "Done" "ZZZZ"+testIndentation :: Number -> Number -> Number+testIndentation x y | x > 0+  = x + y+                    | otherwise+  = y - x++main = Debug.Trace.trace $ min "Done" "ZZZZ"
+ examples/passing/Let2.purs view
@@ -0,0 +1,15 @@+module Main where++test = +  let f :: Number -> Boolean+      f 0 = false+      f n = g (n - 1)++      g :: Number -> Boolean+      g 0 = true+      g n = f (n - 1)++      x = f 1+  in not x++main = Debug.Trace.print test
examples/passing/OperatorAssociativity.purs view
@@ -35,21 +35,13 @@     assert (6 / (3 * 2) == 1)   "6 / (3 * 2) == 1"     assert ((6 / 3) * 2 == 4)   "(6 / 3) * 2 == 4" -    assert (6 % (2 * 2) == 2)   "6 % (2 * 2) == 2"-    assert ((6 % 2) * 2 == 0)   "(6 % 2) * 2 == 0"--    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"
+ examples/passing/OperatorInlining.purs view
@@ -0,0 +1,46 @@+module Main where++import Debug.Trace++main = do++  -- semiringNumber+  print (1 + 2)+  print (1 * 2)++  -- ringNumber+  print (1 - 2)+  print (negate 1)++  -- moduleSemiringNumber+  print (1 / 2)++  -- ordNumber+  print (1 > 2)+  print (1 < 2)+  print (1 <= 2)+  print (1 >= 2)+  print (1 == 2)++  -- eqNumber+  print (1 == 2)+  print (1 /= 2)++  -- eqString+  print ("foo" == "bar")+  print ("foo" /= "bar")++  -- eqBoolean+  print (true == false)+  print (true /= false)++  -- semigroupString+  print ("foo" ++ "bar")+  print ("foo" <> "bar")++  -- latticeBoolean+  print (top && true)+  print (bottom || false)++  -- complementedLatticeBoolean+  print (not true)
examples/passing/Operators.purs view
@@ -61,9 +61,6 @@   test15 :: Number -> Number -> Boolean   test15 a b = const false $ a `test14` b -  test16 :: Number -> Number -> Number-  test16 x y = x .|. y .&. y-   test17 :: Number   test17 = negate (-1) @@ -94,7 +91,6 @@     let t13 = test13 k 1 2     let t14 = test14 1 2     let t15 = test15 1 2-    let t16 = test16 1 2     let t17 = test17     let t18 = test18     let t19 = test19
+ examples/passing/RebindableSyntax.purs view
@@ -0,0 +1,37 @@+module Main where++example1 :: String+example1 = do+  "Do"+  " notation"+  " for"+  " Semigroup"+  where+  (>>=) x f = x <> f unit++(*>) :: forall f a b. (Apply f) => f a -> f b -> f b+(*>) fa fb = const id <$> fa <*> fb++newtype Const a b = Const a++runConst :: forall a b. Const a b -> a+runConst (Const a) = a++instance functorConst :: Functor (Const a) where+  (<$>) _ (Const a) = Const a++instance applyConst :: (Semigroup a) => Apply (Const a) where+  (<*>) (Const a1) (Const a2) = Const (a1 <> a2)++example2 :: Const String Unit+example2 = do+  Const "Do"+  Const " notation"+  Const " for"+  Const " Apply"+  where+  (>>=) x f = x *> f unit++main = do+  Debug.Trace.trace example1+  Debug.Trace.trace $ runConst example2
+ examples/passing/RowConstructors.purs view
@@ -0,0 +1,40 @@+module Main where++type Foo = (x :: Number | (y :: Number | (z :: Number)))+type Bar = (x :: Number, y :: Number, z :: Number)+type Baz = { w :: Number | Bar }++foo :: { | Foo }+foo = { x: 0, y: 0, z: 0 }++bar :: { | Bar }+bar = { x: 0, y: 0, z: 0 }++id' :: Object Foo -> Object Bar+id' = id++foo' :: { | Foo }+foo' = id' foo++bar' :: { | Bar }+bar' = id' bar++baz :: Baz+baz = { x: 0, y: 0, z: 0, w: 0 }++type Quux r = (q :: Number | r)+type Norf r = (q' :: Number | Quux r)++quux :: { f :: { | Foo } | Quux Bar }+quux = { f: foo', x: 0, y: 0, z: 0, q: 0 }++quux' :: { | Norf Bar }+quux' = { x: 0, y: 0, z: 0, q: 0, q': 0 }++wildcard :: { w :: Number | _ } -> Baz+wildcard { w: w } = { x: w, y: w, z: w, w: w }++wildcard' :: { | Quux _ } -> Number+wildcard' { q: q } = q++main = Debug.Trace.trace "Done"
examples/passing/TopLevelCase.purs view
@@ -1,18 +1,28 @@ module Main where -  import Prelude+foreign import jsMod+  """+  function jsMod(x) {+    return function (y) {+      return x % y;+    };+  }+  """ :: Number -> Number -> Number -  gcd :: Number -> Number -> Number-  gcd 0 x = x-  gcd x 0 = x-  gcd x y | x > y = gcd (x % y) y-  gcd x y = gcd (y % x) x+infixl 7 %+(%) = jsMod -  guardsTest (x:xs) | x > 0 = guardsTest xs-  guardsTest xs = xs+gcd :: Number -> Number -> Number+gcd 0 x = x+gcd x 0 = x+gcd x y | x > y = gcd (x % y) y+gcd x y = gcd (y % x) x -  data A = A+guardsTest (x:xs) | x > 0 = guardsTest xs+guardsTest xs = xs -  parseTest A 0 = 0+data A = A -  main = Debug.Trace.trace "Done"+parseTest A 0 = 0++main = Debug.Trace.trace "Done"
prelude/prelude.purs view
@@ -1,156 +1,120 @@ module Prelude-  ( otherwise+  ( Unit(..), unit+  , ($), (#)   , flip   , const   , asTypeOf+  , otherwise+  , (:), cons   , Semigroupoid, (<<<), (>>>)   , Category, id-  , ($), (#)-  , (:), cons-  , Show, show   , Functor, (<$>), (<#>), void   , Apply, (<*>)   , Applicative, pure, liftA1   , Bind, (>>=)   , Monad, return, liftM1, ap+  , Semigroup, (<>), (++)   , Semiring, (+), zero, (*), one   , ModuloSemiring, (/), mod-  , Ring, (-)-  , (%)-  , negate-  , DivisionRing+  , Ring, (-), negate   , Num+  , DivisionRing   , Eq, (==), (/=)-  , Ord, Ordering(..), compare, (<), (>), (<=), (>=)-  , Bits, (.&.), (.|.), (.^.), shl, shr, zshr, complement-  , BoolLike, (&&), (||)-  , not-  , Semigroup, (<>), (++)-  , Unit(..), unit+  , Ordering(..), Ord, compare, (<), (>), (<=), (>=)+  , Bounded, top, bottom+  , Lattice, sup, inf, (||), (&&)+  , BoundedLattice+  , ComplementedLattice, not+  , DistributiveLattice+  , BooleanAlgebra+  , Show, show   ) where -  -- | An alias for `true`, which can be useful in guard clauses:-  -- |-  -- | ```purescript-  -- | max x y | x >= y = x-  -- |         | otherwise = y-  -- | ```+  -- | The `Unit` type has a single inhabitant, called `unit`. It represents+  -- | values with no computational content.   -- |-  otherwise :: Boolean-  otherwise = true+  -- | `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 {} -  -- | Flips the order of the arguments to a function of two arguments.+  -- | `unit` is the sole inhabitant of the `Unit` type.+  unit :: Unit+  unit = Unit {}++  infixr 0 $+  infixl 0 #++  -- | Applies a function to its argument.   -- |   -- | ```purescript-  -- | flip const 1 2 = const 2 1 = 2+  -- | length $ groupBy productCategory $ filter isInStock $ products   -- | ```   -- |-  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.+  -- | is equivalent to:   -- |   -- | ```purescript-  -- | const 1 "hello" = 1+  -- | length (groupBy productCategory (filter isInStock products))   -- | ```   -- |-  const :: forall a b. a -> b -> a-  const a _ = a+  -- | `($)` is different from [`(#)`](#-2) because it is right-infix instead of+  -- | left: `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 -  -- | This function returns its first argument, and can be used to assert type equalities.-  -- | This can be useful when types are otherwise ambiguous.+  -- | Applies an argument to a function.   -- |   -- | ```purescript-  -- | main = print $ [] `asTypeOf` [0]+  -- | products # filter isInStock # groupBy productCategory # length   -- | ```   -- |-  -- | If instead, we had written `main = print []`, the type of the argument `[]` would have-  -- | been ambiguous, resulting in a compile-time error.-  asTypeOf :: forall a. a -> a -> a-  asTypeOf x _ = x--  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--  instance categoryArr :: Category (->) where-    id x = x--  infixr 0 $-  infixl 0 #--  -- | Applies a function to its argument+  -- | is equivalent to:   -- |   -- | ```purescript-  -- | length $ groupBy productCategory $ filter isInStock products+  -- | length (groupBy productCategory (filter isInStock products))   -- | ```   -- |-  -- | is equivalent to+  -- | `(#)` is different from [`($)`](#-1) because it is left-infix instead of+  -- | right: `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++  -- | Flips the order of the arguments to a function of two arguments.   -- |   -- | ```purescript-  -- | length (groupBy productCategory (filter isInStock (products)))+  -- | flip const 1 2 = const 2 1 = 2   -- | ```-  -- |-  -- | `($)` 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+  flip :: forall a b c. (a -> b -> c) -> b -> a -> c+  flip f b a = f a b -  -- | Applies a function to its argument+  -- | Returns its first argument and ignores its second.   -- |   -- | ```purescript-  -- | products # groupBy productCategory # filter isInStock # length+  -- | const 1 "hello" = 1   -- | ```-  -- |-  -- | is equivalent to+  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.   -- |   -- | ```purescript-  -- | length (groupBy productCategory (filter isInStock (products)))+  -- | main = print $ [] `asTypeOf` [0]   -- | ```   -- |-  -- | `(#)` 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 :+  -- | If instead, we had written `main = print []`, the type of the argument+  -- | `[]` would have been ambiguous, resulting in a compile-time error.+  asTypeOf :: forall a. a -> a -> a+  asTypeOf x _ = x -  -- | An infix alias for `cons`.+  -- | An alias for `true`, which can be useful in guard clauses:   -- |-  -- | Note, the running time of this function is `O(n)`.-  (:) :: forall a. a -> [a] -> [a]-  (:) = cons+  -- | ```purescript+  -- | max x y | x >= y    = x+  -- |         | otherwise = y+  -- | ```+  otherwise :: Boolean+  otherwise = true    -- | Attaches an element to the front of an array, creating a new array.   -- |@@ -168,72 +132,70 @@     }     """ :: 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--  foreign import showStringImpl-    """-    function showStringImpl(s) {-      return JSON.stringify(s);-    }-    """ :: String -> String+  infixr 6 : -  instance showUnit :: Show Unit where-    show (Unit {}) = "Unit {}"+  -- | An infix alias for `cons`.+  -- |+  -- | Note, the running time of this function is `O(n)`.+  (:) :: forall a. a -> [a] -> [a]+  (:) = cons -  instance showString :: Show String where-    show = showStringImpl+  infixr 9 >>>+  infixr 9 <<< -  instance showBoolean :: Show Boolean where-    show true = "true"-    show false = "false"+  -- | A `Semigroupoid` is similar to a [`Category`](#category) but does not+  -- | require an identity element `id`, just composable morphisms.+  -- |+  -- | `Semigroupoid`s must satisfy the following law:+  -- |+  -- | - 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 -  foreign import showNumberImpl-    """-    function showNumberImpl(n) {-      return n.toString();-    }-    """ :: Number -> String+  instance semigroupoidArr :: Semigroupoid (->) where+    (<<<) f g x = f (g x) -  instance showNumber :: Show Number where-    show = showNumberImpl+  -- | 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 -  foreign import showArrayImpl-    """-    function showArrayImpl(f) {-      return function(xs) {-        var ss = [];-        for (var i = 0, l = xs.length; i < l; i++) {-          ss[i] = f(xs[i]);-        }-        return '[' + ss.join(',') + ']';-      };-    }-    """ :: forall a. (a -> String) -> [a] -> String+  -- | `Category`s consist of objects and composable morphisms between them, and+  -- | as such are [`Semigroupoids`](#semigroupoid), but unlike `semigroupoids`+  -- | must have an identity element.+  -- |+  -- | Instances must satisfy the following law in addition to the+  -- | `Semigroupoid` law:+  -- |+  -- | - Identity: `id <<< p = p <<< id = p`+  class (Semigroupoid a) <= Category a where+    id :: forall t. a t t -  instance showArray :: (Show a) => Show [a] where-    show = showArrayImpl show+  instance categoryArr :: Category (->) where+    id x = x    infixl 4 <$>   infixl 1 <#> -  -- | A `Functor` is a type constructor which supports a mapping operation `(<$>)`.+  -- | 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.+  -- | `(<$>)` 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:+  -- | Instances must 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 +  instance functorArr :: Functor ((->) r) where+    (<$>) = (<<<)+   -- | `(<#>)` is `(<$>)` with its arguments reversed. For example:   -- |   -- | ```purescript@@ -242,10 +204,12 @@   (<#>) :: 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.+  -- | 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:+  -- | `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@@ -257,48 +221,69 @@    infixl 4 <*> -  -- | The `Apply` class provides the `(<*>)` which is used to apply a function to an argument under a type constructor.+  -- | 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:+  -- | `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`.+  -- | `(<*>)` 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:+  -- | Instances must satisfy the following law in addition to the `Functor`+  -- | laws:   -- |-  -- | - Associative Composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)`+  -- | - 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`.+  instance applyArr :: Apply ((->) r) where+    (<*>) f g x = f x (g x)++  -- | 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.+  -- | 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:+  -- | Instances must satisfy the following laws in addition to the `Apply`+  -- | 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.+  instance applicativeArr :: Applicative ((->) r) where+    pure = const++  -- | `return` is an alias for `pure`.+  return :: forall m a. (Applicative m) => a -> m a+  return = pure++  -- | `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:+  -- | `liftA1` can therefore be used to write [`Functor`](#functor) instances+  -- | as follows:   -- |   -- | ```purescript   -- | instance functorF :: Functor F where@@ -309,8 +294,9 @@    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 `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:   -- |@@ -321,15 +307,13 @@   -- |   -- | where the function argument of `f` is given the name `y`.   -- |-  -- | `Bind` instances should satisfy the following law:+  -- | Instances must satisfy the following law in addition to the `Apply`+  -- | laws:   -- |   -- | - 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:+  -- | Associativity tells us that we can regroup operations which use `do`+  -- | notation so that we can unambiguously write, for example:   -- |   -- | ```purescript   -- | do x <- m1@@ -339,29 +323,29 @@   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.+  instance bindArr :: Bind ((->) r) where+    (>>=) m f x = f (m x) x++  -- | 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:+  -- | Instances must satisfy the following laws in addition to the+  -- | `Applicative` and `Bind` 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+  instance monadArr :: Monad ((->) r) -  -- | `liftM1` provides a default implementation of `(<$>)` for any [`Monad`](#monad),-  -- | without using `(<$>)` as provided by the [`Functor`](#functor)-[`Monad`](#monad) superclass relationship.+  -- | `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:+  -- | `liftM1` can therefore be used to write [`Functor`](#functor) instances+  -- | as follows:   -- |   -- | ```purescript   -- | instance functorF :: Functor F where@@ -372,10 +356,12 @@     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` 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:+  -- | `ap` can therefore be used to write [`Apply`](#apply) instances as+  -- | follows:   -- |   -- | ```purescript   -- | instance applyF :: Apply F where@@ -387,69 +373,153 @@     a' <- a     return (f' a') -  instance functorArr :: Functor ((->) r) where-    (<$>) = (<<<)+  infixr 5 <>+  infixr 5 ++ -  instance applyArr :: Apply ((->) r) where-    (<*>) f g x = f x (g x)+  -- | The `Semigroup` type class identifies an associative operation on a type.+  -- |+  -- | Instances are required to satisfy the following law:+  -- |+  -- | - Associativity: `(x <> y) <> z = x <> (y <> z)`+  -- |+  -- | One example of a `Semigroup` is `String`, with `(<>)` defined as string+  -- | concatenation.+  class Semigroup a where+    (<>) :: a -> a -> a -  instance applicativeArr :: Applicative ((->) r) where-    pure = const+  -- | `(++)` is an alias for `(<>)`.+  (++) :: forall s. (Semigroup s) => s -> s -> s+  (++) = (<>) -  instance bindArr :: Bind ((->) r) where-    (>>=) m f x = f (m x) x+  instance semigroupString :: Semigroup String where+    (<>) = concatString -  instance monadArr :: Monad ((->) r)+  instance semigroupUnit :: Semigroup Unit where+    (<>) _ _ = unit -  infixl 7 *-  infixl 7 /-  infixl 7 %+  instance semigroupArr :: (Semigroup s') => Semigroup (s -> s') where+    (<>) f g = \x -> f x <> g x -  infixl 6 -+  instance semigroupOrdering :: Semigroup Ordering where+    (<>) LT _ = LT+    (<>) GT _ = GT+    (<>) EQ y = y++  foreign import concatString+    """+    function concatString(s1) {+      return function(s2) {+        return s1 + s2;+      };+    }+    """ :: String -> String -> String+   infixl 6 ++  infixl 7 * -  -- | Addition and multiplication, satisfying the following laws:+  -- | The `Semiring` class is for types that support an addition and+  -- | multiplication operation.   -- |-  -- | - `a` is a commutative monoid under addition-  -- | - `a` is a monoid under multiplication-  -- | - multiplication distributes over addition-  -- | - multiplication by `zero` annihilates `a`+  -- | Instances must satisfy the following laws:   -- |+  -- | - Commutative monoid under addition:+  -- |   - Associativity: `(a + b) + c = a + (b + c)`+  -- |   - Identity: `zero + a = a + zero = a`+  -- |   - Commutative: `a + b = b + a`+  -- | - Monoid under multiplication:+  -- |   - Associativity: `(a * b) * c = a * (b * c)`+  -- |   - Identity: `one * a = a * one = a`+  -- | - Multiplication distributes over addition:+  -- |   - Left distributivity: `a * (b + c) = (a * b) + (a * c)`+  -- |   - Right distributivity: `(a + b) * c = (a * c) + (b * c)`+  -- | - Annihiliation: `zero * a = a * zero = zero`   class Semiring a where     (+)  :: a -> a -> a     zero :: a     (*)  :: a -> a -> a     one  :: 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+  instance semiringNumber :: Semiring Number where+    (+) = numAdd+    zero = 0+    (*) = numMul+    one = 1 -  -- | Addition, multiplication, and subtraction.-  -- |-  -- | Has the same laws as `Semiring` but additionally satisfying:+  instance semiringUnit :: Semiring Unit where+    (+) _ _ = unit+    zero = unit+    (*) _ _ = unit+    one = unit++  infixl 6 -++  -- | The `Ring` class is for types that support addition, multiplication,+  -- | and subtraction operations.   -- |-  -- | - `a` is an abelian group under addition+  -- | Instances must satisfy the following law in addition to the `Semiring`+  -- | laws:   -- |+  -- | - Additive inverse: `a + (-a) = (-a) + a = zero`   class (Semiring a) <= Ring a where     (-) :: a -> a -> a +  instance ringNumber :: Ring Number where+    (-) = numSub++  instance ringUnit :: Ring Unit where+    (-) _ _ = unit+   negate :: forall a. (Ring a) => a -> a   negate a = zero - a -  -- | Ring where every nonzero element has a multiplicative inverse so that:+  infixl 7 /++  -- | The `ModuloSemiring` class is for types that support addition,+  -- | multiplication, division, and modulo (division remainder) operations.   -- |-  -- | - ```a `mod` b = zero```+  -- | Instances must satisfy the following law in addition to the `Semiring`+  -- | laws:   -- |+  -- | - Remainder: `a / b * b + (a `mod` b) = a`+  class (Semiring a) <= ModuloSemiring a where+    (/) :: a -> a -> a+    mod :: a -> a -> a++  instance moduloSemiringNumber :: ModuloSemiring Number where+    (/) = numDiv+    mod _ _ = 0++  instance moduloSemiringUnit :: ModuloSemiring Unit where+    (/) _ _ = unit+    mod _ _ = unit++  -- | A `Ring` where every nonzero element has a multiplicative inverse.+  -- |+  -- | Instances must satisfy the following law in addition to the `Ring` and+  -- | `ModuloSemiring` laws:+  -- |+  -- | - Multiplicative inverse: `(one / x) * x = one`+  -- |+  -- | As a consequence of this ```a `mod` b = zero``` as no divide operation+  -- | will have a remainder.   class (Ring a, ModuloSemiring a) <= DivisionRing a -  -- | A commutative field+  instance divisionRingNumber :: DivisionRing Number++  instance divisionRingUnit :: DivisionRing Unit++  -- | The `Num` class is for types that are commutative fields.+  -- |+  -- | Instances must satisfy the following law in addition to the+  -- | `DivisionRing` laws:+  -- |+  -- | - Commutative multiplication: `a * b = b * a`   class (DivisionRing a) <= Num a +  instance numNumber :: Num Number++  instance numUnit :: Num Unit+   foreign import numAdd     """     function numAdd(n1) {@@ -459,15 +529,6 @@     }     """ :: Number -> Number -> Number -  foreign import numSub-    """-    function numSub(n1) {-      return function(n2) {-        return n1 - n2;-      };-    }-    """ :: Number -> Number -> Number-   foreign import numMul     """     function numMul(n1) {@@ -486,44 +547,15 @@     }     """ :: Number -> Number -> Number -  foreign import numMod+  foreign import numSub     """-    function numMod(n1) {+    function numSub(n1) {       return function(n2) {-        return n1 % n2;+        return n1 - n2;       };     }     """ :: Number -> Number -> Number -  (%) = numMod--  instance semiringNumber :: Semiring Number where-    (+) = numAdd-    zero = 0-    (*) = numMul-    one = 1--  instance ringNumber :: Ring Number where-    (-) = numSub--  instance moduloSemiringNumber :: ModuloSemiring Number where-    (/) = numDiv-    mod _ _ = 0--  instance divisionRingNumber :: DivisionRing Number--  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 /= @@ -541,6 +573,33 @@     (==) :: a -> a -> Boolean     (/=) :: a -> a -> Boolean +  instance eqBoolean :: Eq Boolean where+    (==) = refEq+    (/=) = refIneq++  instance eqNumber :: Eq Number where+    (==) = refEq+    (/=) = refIneq++  instance eqString :: Eq String where+    (==) = refEq+    (/=) = refIneq++  instance eqUnit :: Eq Unit where+    (==) _ _ = true+    (/=) _ _ = false++  instance eqArray :: (Eq a) => Eq [a] where+    (==) = eqArrayImpl (==)+    (/=) xs ys = not (xs == ys)++  instance eqOrdering :: Eq Ordering where+    (==) LT LT = true+    (==) GT GT = true+    (==) EQ EQ = true+    (==) _  _  = false+    (/=) x y = not (x == y)+   foreign import refEq     """     function refEq(r1) {@@ -559,22 +618,6 @@     }     """ :: forall a. a -> a -> Boolean -  instance eqUnit :: Eq Unit where-    (==) (Unit {}) (Unit {}) = true-    (/=) (Unit {}) (Unit {}) = false--  instance eqString :: Eq String where-    (==) = refEq-    (/=) = refIneq--  instance eqNumber :: Eq Number where-    (==) = refEq-    (/=) = refIneq--  instance eqBoolean :: Eq Boolean where-    (==) = refEq-    (/=) = refIneq-   foreign import eqArrayImpl     """     function eqArrayImpl(f) {@@ -590,34 +633,14 @@     }     """ :: forall a. (a -> a -> Boolean) -> [a] -> [a] -> Boolean -  instance eqArray :: (Eq a) => Eq [a] where-    (==) xs ys = eqArrayImpl (==) xs ys-    (/=) xs ys = not (xs == ys)--  -- | The `Ordering` data type represents the three possible outcomes of comparing two values:+  -- | 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-    (==) LT LT = true-    (==) GT GT = true-    (==) EQ EQ = true-    (==) _  _  = false-    (/=) x y = not (x == y)--  instance showOrdering :: Show Ordering where-    show LT = "LT"-    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_:@@ -625,11 +648,45 @@   -- | - 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 +  instance ordBoolean :: Ord Boolean where+    compare false false = EQ+    compare false true  = LT+    compare true  true  = EQ+    compare true  false = GT++  instance ordNumber :: Ord Number where+    compare = unsafeCompare++  instance ordString :: Ord String where+    compare = unsafeCompare++  instance ordUnit :: Ord Unit where+    compare _ _ = EQ++  instance ordArray :: (Ord a) => Ord [a] where+    compare [] [] = EQ+    compare [] _ = LT+    compare _ [] = GT+    compare (x:xs) (y:ys) = case compare x y of+      EQ -> compare xs ys+      other -> other++  instance ordOrdering :: Ord Ordering where+    compare LT LT = EQ+    compare EQ EQ = EQ+    compare GT GT = EQ+    compare LT _  = LT+    compare EQ LT = GT+    compare EQ GT = LT+    compare GT _  = GT+   infixl 4 <+  infixl 4 >+  infixl 4 <=+  infixl 4 >=    -- | Test whether one value is _strictly less than_ another.   (<) :: forall a. (Ord a) => a -> a -> Boolean@@ -637,30 +694,27 @@     LT -> true     _ -> false -  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     _ -> false -  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     _ -> true -  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     _ -> true +  unsafeCompare :: forall a. a -> a -> Ordering+  unsafeCompare = unsafeCompareImpl LT EQ GT+   foreign import unsafeCompareImpl     """     function unsafeCompareImpl(lt) {@@ -676,137 +730,131 @@     }     """ :: forall a. Ordering -> Ordering -> Ordering -> a -> a -> Ordering -  unsafeCompare :: forall a. a -> a -> Ordering-  unsafeCompare = unsafeCompareImpl LT EQ GT--  instance ordUnit :: Ord Unit where-    compare (Unit {}) (Unit {}) = EQ+  -- | The `Bounded` type class represents types that are finite partially+  -- | ordered sets.+  -- |+  -- | Instances should satisfy the following law in addition to the `Ord` laws:+  -- |+  -- | - Ordering: `bottom <= a <= top`+  class (Ord a) <= Bounded a where+    top :: a+    bottom :: a -  instance ordBoolean :: Ord Boolean where-    compare false false = EQ-    compare false true  = LT-    compare true  true  = EQ-    compare true  false = GT+  instance boundedBoolean :: Bounded Boolean where+    top = true+    bottom = false -  instance ordNumber :: Ord Number where-    compare = unsafeCompare+  instance boundedUnit :: Bounded Unit where+    top = unit+    bottom = unit -  instance ordString :: Ord String where-    compare = unsafeCompare+  instance boundedOrdering :: Bounded Ordering where+    top = GT+    bottom = LT -  instance ordArray :: (Ord a) => Ord [a] where-    compare [] [] = EQ-    compare [] _ = LT-    compare _ [] = GT-    compare (x:xs) (y:ys) = case compare x y of-      EQ -> compare xs ys-      other -> other+  -- | The `Lattice` type class represents types that are partially ordered+  -- | sets with a supremum (`sup` or `||`) and infimum (`inf` or `&&`).+  -- |+  -- | Instances should satisfy the following laws in addition to the `Ord`+  -- | laws:+  -- |+  -- | - Associativity:+  -- |   - `a || (b || c) = (a || b) || c`+  -- |   - `a && (b && c) = (a && b) && c`+  -- | - Commutativity:+  -- |   - `a || b = b || a`+  -- |   - `a && b = b && a`+  -- | - Absorption:+  -- |   - `a || (a && b) = a`+  -- |   - `a && (a || b) = a`+  -- | - Idempotent:+  -- |   - `a || a = a`+  -- |   - `a && a = a`+  class (Ord a) <= Lattice a where+    sup :: a -> a -> a+    inf :: a -> a -> a -  infixl 10 .&.-  infixl 10 .|.-  infixl 10 .^.+  instance latticeBoolean :: Lattice Boolean where+    sup = boolOr+    inf = boolAnd -  -- | The `Bits` type class identifies types which support bitwise operations.-  class Bits b where-    (.&.) :: b -> b -> b-    (.|.) :: b -> b -> b-    (.^.) :: b -> b -> b-    shl :: b -> Number -> b-    shr :: b -> Number -> b-    zshr :: b -> Number -> b-    complement :: b -> b+  instance latticeUnit :: Lattice Unit where+    sup _ _ = unit+    inf _ _ = unit -  foreign import numShl-    """-    function numShl(n1) {-      return function(n2) {-        return n1 << n2;-      };-    }-    """ :: Number -> Number -> Number+  infixr 2 ||+  infixr 3 && -  foreign import numShr-    """-    function numShr(n1) {-      return function(n2) {-        return n1 >> n2;-      };-    }-    """ :: Number -> Number -> Number+  -- | The `sup` operator.+  (||) :: forall a. (Lattice a) => a -> a -> a+  (||) = sup -  foreign import numZshr-    """-    function numZshr(n1) {-      return function(n2) {-        return n1 >>> n2;-      };-    }-    """ :: Number -> Number -> Number+  -- | The `inf` operator.+  (&&) :: forall a. (Lattice a) => a -> a -> a+  (&&) = inf -  foreign import numAnd-    """-    function numAnd(n1) {-      return function(n2) {-        return n1 & n2;-      };-    }-    """ :: Number -> Number -> Number+  -- | The `BoundedLattice` type class represents types that are finite+  -- | lattices.+  -- |+  -- | Instances should satisfy the following law in addition to the `Lattice`+  -- | and `Bounded` laws:+  -- |+  -- | - Identity:+  -- |   - `a || bottom = a`+  -- |   - `a && top = a`+  -- | - Annihiliation:+  -- |   - `a || top = top`+  -- |   - `a && bottom = bottom`+  class (Bounded a, Lattice a) <= BoundedLattice a -  foreign import numOr-    """-    function numOr(n1) {-      return function(n2) {-        return n1 | n2;-      };-    }-    """ :: Number -> Number -> Number+  instance boundedLatticeBoolean :: BoundedLattice Boolean -  foreign import numXor-    """-    function numXor(n1) {-      return function(n2) {-        return n1 ^ n2;-      };-    }-    """ :: Number -> Number -> Number+  instance boundedLatticeUnit :: BoundedLattice Unit -  foreign import numComplement-    """-    function numComplement(n) {-      return ~n;-    }-    """ :: Number -> Number+  -- | The `ComplementedLattice` type class represents types that are lattices+  -- | where every member is also uniquely complemented.+  -- |+  -- | Instances should satisfy the following law in addition to the+  -- | `BoundedLattice` laws:+  -- |+  -- | - Complemented:+  -- |   - `not a || a == top`+  -- |   - `not a && a == bottom`+  -- | - Double negation:+  -- |   - `not <<< not == id`+  class (BoundedLattice a) <= ComplementedLattice a where+    not :: a -> a -  instance bitsNumber :: Bits Number where-    (.&.) = numAnd-    (.|.) = numOr-    (.^.) = numXor-    shl = numShl-    shr = numShr-    zshr = numZshr-    complement = numComplement+  instance complementedLatticeBoolean :: ComplementedLattice Boolean where+    not = boolNot -  infixr 2 ||-  infixr 3 &&+  instance complementedLatticeUnit :: ComplementedLattice Unit where+    not _ = unit -  -- | The `BoolLike` type class identifies types which support Boolean operations.+  -- | The `DistributiveLattice` type class represents types that are lattices+  -- | where the `&&` and `||` distribute over each other.   -- |-  -- | `BoolLike` instances are required to satisfy the laws of a _Boolean algebra_.+  -- | Instances should satisfy the following law in addition to the `Lattice`+  -- | laws:   -- |-  class BoolLike b where-    (&&) :: b -> b -> b-    (||) :: b -> b -> b-    not :: b -> b+  -- | - Distributivity: `x && (y || z) = (x && y) || (x && z)`+  class (Lattice a) <= DistributiveLattice a -  foreign import boolAnd-    """-    function boolAnd(b1) {-      return function(b2) {-        return b1 && b2;-      };-    }-    """  :: Boolean -> Boolean -> Boolean+  instance distributiveLatticeBoolean :: DistributiveLattice Boolean +  instance distributiveLatticeUnit :: DistributiveLattice Unit++  -- | The `BooleanAlgebra` type class represents types that are Boolean+  -- | algebras, also known as Boolean lattices.+  -- |+  -- | Instances should satisfy the `ComplementedLattice` and+  -- | `DistributiveLattice` laws.+  class (ComplementedLattice a, DistributiveLattice a) <= BooleanAlgebra a++  instance booleanAlgebraBoolean :: BooleanAlgebra Boolean++  instance booleanAlgebraUnit :: BooleanAlgebra Unit+   foreign import boolOr     """     function boolOr(b1) {@@ -816,6 +864,15 @@     }     """ :: Boolean -> Boolean -> Boolean +  foreign import boolAnd+    """+    function boolAnd(b1) {+      return function(b2) {+        return b1 && b2;+      };+    }+    """  :: Boolean -> Boolean -> Boolean+   foreign import boolNot     """     function boolNot(b) {@@ -823,46 +880,62 @@     }     """ :: Boolean -> Boolean -  instance boolLikeBoolean :: BoolLike Boolean where-    (&&) = boolAnd-    (||) = boolOr-    not = boolNot+  -- | 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 -  infixr 5 <>+  instance showBoolean :: Show Boolean where+    show true = "true"+    show false = "false" -  -- | 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+  instance showNumber :: Show Number where+    show = showNumberImpl -  foreign import concatString-    """-    function concatString(s1) {-      return function(s2) {-        return s1 + s2;-      };-    }-    """ :: String -> String -> String+  instance showString :: Show String where+    show = showStringImpl -  instance semigroupUnit :: Semigroup Unit where-    (<>) (Unit {}) (Unit {}) = Unit {}+  instance showUnit :: Show Unit where+    show _ = "unit" -  instance semigroupString :: Semigroup String where-    (<>) = concatString+  instance showArray :: (Show a) => Show [a] where+    show = showArrayImpl show -  instance semigroupArr :: (Semigroup s') => Semigroup (s -> s') where-    (<>) f g = \x -> f x <> g x+  instance showOrdering :: Show Ordering where+    show LT = "LT"+    show GT = "GT"+    show EQ = "EQ" -  infixr 5 +++  foreign import showNumberImpl+    """+    function showNumberImpl(n) {+      return n.toString();+    }+    """ :: Number -> String -  -- | `(++)` is an alias for `(<>)`.-  (++) :: forall s. (Semigroup s) => s -> s -> s-  (++) = (<>)+  foreign import showStringImpl+    """+    function showStringImpl(s) {+      return JSON.stringify(s);+    }+    """ :: String -> String++  foreign import showArrayImpl+    """+    function showArrayImpl(f) {+      return function(xs) {+        var ss = [];+        for (var i = 0, l = xs.length; i < l; i++) {+          ss[i] = f(xs[i]);+        }+        return '[' + ss.join(',') + ']';+      };+    }+    """ :: forall a. (a -> String) -> [a] -> String  module Data.Function where 
psc-make/Main.hs view
@@ -52,27 +52,29 @@   content <- forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readFile inFile   return (if ioNoPrelude then content else (Left P.RebuildNever, P.prelude) : content) -newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (ExceptT String IO) a }-  deriving (Functor, Applicative, Monad, MonadIO, MonadError String, MonadReader (P.Options P.Make))+newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (ExceptT P.MultipleErrors IO) a }+  deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadReader (P.Options P.Make)) -runMake :: P.Options P.Make -> Make a -> IO (Either String a)+runMake :: P.Options P.Make -> Make a -> IO (Either P.MultipleErrors a) runMake opts = runExceptT . flip runReaderT opts . unMake -makeIO :: IO a -> Make a-makeIO = Make . lift . ExceptT . fmap (either (Left . show) Right) . tryIOError+makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a+makeIO f io = do+  e <- liftIO $ tryIOError io+  either (throwError . P.errorMessage . f) return e  instance P.MonadMake Make where-  getTimestamp path = makeIO $ do+  getTimestamp path = makeIO (const (P.CannotGetFileInfo path)) $ do     exists <- doesFileExist path     traverse (const $ getModificationTime path) $ guard exists-  readTextFile path = makeIO $ do+  readTextFile path = makeIO (const (P.CannotReadFile path))$ do     putStrLn $ "Reading " ++ path     readFile path-  writeTextFile path text = makeIO $ do+  writeTextFile path text = makeIO (const (P.CannotWriteFile path)) $ do     mkdirp path     putStrLn $ "Writing " ++ path     writeFile path text-  progress = makeIO . putStrLn+  progress = liftIO . putStrLn  compile :: PSCMakeOptions -> IO () compile (PSCMakeOptions input outputDir opts usePrefix) = do@@ -84,8 +86,8 @@     Right ms -> do       e <- runMake opts $ P.make outputDir ms prefix       case e of-        Left err -> do-          putStrLn err+        Left errs -> do+          putStrLn (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)           exitFailure         Right _ -> do           exitSuccess@@ -155,8 +157,8 @@                     <*> noMagicDo                     <*> pure Nothing                     <*> noOpts-                    <*> (not <$> comments)                     <*> verboseErrors+                    <*> (not <$> comments)                     <*> pure P.MakeOptions  pscMakeOptions :: Parser PSCMakeOptions
psc/Main.hs view
@@ -63,8 +63,8 @@       exitFailure     Right ms -> do       case P.compile (map snd ms) prefix `runReaderT` opts of-        Left err -> do-          hPutStrLn stderr err+        Left errs -> do+          hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)           exitFailure         Right (js, exts, _) -> do           case output of
− psci/Commands.hs
@@ -1,78 +0,0 @@------------------------------------------------------------------------------------ Module      :  Commands--- Copyright   :  (c) Phil Freeman 2014--- License     :  MIT------ Maintainer  :  Phil Freeman <paf31@cantab.net>--- Stability   :  experimental--- Portability :------ |--- Commands for PSCI.-----------------------------------------------------------------------------------module Commands where--import Language.PureScript---- |--- Valid Meta-commands for PSCI----data Command-  -- |-  -- A purescript expression-  ---  = Expression Expr-  -- |-  -- Show the help command-  ---  | Help-  -- |-  -- Import a module from a loaded file-  ---  | Import ImportedModule-  -- |-  -- Browse a module-  ---  | Browse ModuleName-  -- |-  -- Load a file for use with importing-  ---  | LoadFile FilePath-  -- |-  -- Exit PSCI-  ---  | Quit-  -- |-  -- Reset the state of the REPL-  ---  | Reset-  -- |-  -- Add some declarations to the current evaluation context.-  ---  | Decls [Declaration]-  -- |-  -- Find the type of an expression-  ---  | TypeOf Expr-  -- |-  -- Find the kind of an expression-  ---  | KindOf Type-  -- |-  -- Show command-  ---  | Show String---- | All of the data that is contained by an ImportDeclaration in the AST.--- That is:------ * 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/Completion.hs view
@@ -0,0 +1,232 @@+module Completion where++import Data.Maybe (mapMaybe)+import Data.List (nub, nubBy, sortBy, isPrefixOf, stripPrefix)+import Data.Char (isUpper)+import Data.Function (on)+import Data.Traversable (traverse)++import Control.Applicative ((<$>), (<*>))+import Control.Monad.Trans.Reader (asks, runReaderT, ReaderT)+import Control.Monad.Trans.State.Strict++import System.Console.Haskeline++import qualified Language.PureScript as P+import qualified Language.PureScript.Names as N++import qualified Directive as D+import Types++-- Completions may read the state, but not modify it.+type CompletionM = ReaderT PSCiState IO++-- Lift a `CompletionM` action to a `StateT PSCiState IO` one.+liftCompletionM :: CompletionM a -> StateT PSCiState IO a+liftCompletionM act = StateT (\s -> (\a -> (a, s)) <$> runReaderT act s)++-- Haskeline completions++data CompletionContext+  = CtxDirective String+  | CtxFilePath String+  | CtxModule+  | CtxIdentifier+  | CtxType+  | CtxFixed String+  deriving (Show)++-- |+-- Loads module, function, and file completions.+--+completion :: CompletionFunc (StateT PSCiState IO)+completion = liftCompletionM . completion'++completion' :: CompletionFunc CompletionM+completion' = completeWordWithPrev Nothing " \t\n\r" findCompletions++-- |+-- Decide what kind of completion we need based on input. This function expects+-- a list of complete words (to the left of the cursor) as the first argument,+-- and the current word as the second argument.+completionContext :: [String] -> String -> [CompletionContext]+completionContext [] _ = [CtxDirective "", CtxIdentifier, CtxFixed "import"]+completionContext ws w | headSatisfies (":" `isPrefixOf`) ws = completeDirective ws w+completionContext ws w | headSatisfies (== "import") ws = completeImport ws w+completionContext _ _ = [CtxIdentifier]++completeDirective :: [String] -> String -> [CompletionContext]+completeDirective ws w =+  case ws of+    []    -> [CtxDirective w]+    [dir] -> case D.directivesFor <$> stripPrefix ":" dir of+                -- only offer completions if the directive is unambiguous+                Just [dir'] -> directiveArg w dir'+                _           -> []++    -- All directives take exactly one argument. If we haven't yet matched,+    -- that means one argument has already been supplied. So don't complete+    -- any others.+    _     -> []++directiveArg :: String -> Directive -> [CompletionContext]+directiveArg _ Browse = [CtxModule]+directiveArg w Load   = [CtxFilePath w]+directiveArg _ Quit   = []+directiveArg _ Reset  = []+directiveArg _ Help   = []+directiveArg _ Show   = map CtxFixed replQueryStrings+directiveArg _ Type   = [CtxIdentifier]+directiveArg _ Kind   = [CtxType]++completeImport :: [String] -> String -> [CompletionContext]+completeImport ws w' =+  case (ws, w') of+    (["import"], w) | headSatisfies isUpper w -> [CtxModule]+    (["import"], _)                           -> [CtxModule, CtxFixed "qualified"]+    (["import", "qualified"], _)              -> [CtxModule]+    _                                         -> []++headSatisfies :: (a -> Bool) -> [a] -> Bool+headSatisfies p str =+  case str of+    (c:_)  -> p c+    _     -> False++-- | Callback for Haskeline's `completeWordWithPrev`.+-- Expects:+--   * Line contents to the left of the word, reversed+--   * Word to be completed+findCompletions :: String -> String -> CompletionM [Completion]+findCompletions prev word = do+  let ctx = completionContext (words (reverse prev)) word+  completions <- concat <$> traverse getCompletions ctx+  return $ sortBy directivesFirst completions+  where+  getCompletions :: CompletionContext -> CompletionM [Completion]+  getCompletions = fmap (mapMaybe (either (prefixedBy word) Just)) . getCompletion++  prefixedBy :: String -> String -> Maybe Completion+  prefixedBy w cand = if w `isPrefixOf` cand+                        then Just (simpleCompletion cand)+                        else Nothing++getCompletion :: CompletionContext -> CompletionM [Either String Completion]+getCompletion ctx =+  case ctx of+    CtxFilePath f        -> map Right <$> listFiles f+    CtxModule            -> map Left <$> getModuleNames+    CtxIdentifier        -> map Left <$> ((++) <$> getIdentNames <*> getDctorNames)+    CtxType              -> map Left <$> getTypeNames+    CtxFixed str         -> return [Left str]+    CtxDirective d       -> return (map Left (completeDirectives d))++  where+  completeDirectives :: String -> [String]+  completeDirectives = map (':' :) . D.directiveStringsFor+++getLoadedModules :: CompletionM [P.Module]+getLoadedModules = asks (map snd . psciLoadedModules)++getImportedModules :: CompletionM [ImportedModule]+getImportedModules = asks psciImportedModules++getModuleNames :: CompletionM [String]+getModuleNames = moduleNames <$> getLoadedModules++mapLoadedModulesAndQualify :: (Show a) => (P.Module -> [(a, P.Declaration)]) -> CompletionM [String]+mapLoadedModulesAndQualify f = do+  ms <- getLoadedModules+  let argPairs = do m <- ms+                    fm <- f m+                    return (m, fm)+  concat <$> traverse (uncurry getAllQualifications) argPairs++getIdentNames :: CompletionM [String]+getIdentNames = mapLoadedModulesAndQualify identNames++getDctorNames :: CompletionM [String]+getDctorNames = mapLoadedModulesAndQualify dctorNames++getTypeNames :: CompletionM [String]+getTypeNames = mapLoadedModulesAndQualify typeDecls++-- | Given a module and a declaration in that module, return all possible ways+-- it could have been referenced given the current PSCiState - including fully+-- qualified, qualified using an alias, and unqualified.+getAllQualifications :: (Show a) => P.Module -> (a, P.Declaration) -> CompletionM [String]+getAllQualifications m (declName, decl) = do+  imports <- getAllImportsOf m+  let fullyQualified = qualifyWith (Just (P.getModuleName m))+  let otherQuals = nub (concatMap qualificationsUsing imports)+  return $ fullyQualified : otherQuals+  where+  qualifyWith mMod = show (P.Qualified mMod declName)+  referencedBy refs = P.isExported (Just refs) decl++  qualificationsUsing (_, importType, asQ') =+    let q = qualifyWith asQ'+    in case importType of+          P.Implicit      -> [q]+          P.Explicit refs -> if referencedBy refs+                               then [q]+                               else []+          P.Hiding refs   -> if referencedBy refs+                               then []+                               else [q]+++-- | Returns all the ImportedModule values referring to imports of a particular+-- module.+getAllImportsOf :: P.Module -> CompletionM [ImportedModule]+getAllImportsOf = asks . allImportsOf++nubOnFst :: Eq a => [(a, b)] -> [(a, b)]+nubOnFst = nubBy ((==) `on` fst)++typeDecls :: P.Module -> [(N.ProperName, P.Declaration)]+typeDecls = mapMaybe getTypeName . filter P.isDataDecl . P.exportedDeclarations+  where+  getTypeName :: P.Declaration -> Maybe (N.ProperName, P.Declaration)+  getTypeName d@(P.TypeSynonymDeclaration name _ _) = Just (name, d)+  getTypeName d@(P.DataDeclaration _ name _ _) = Just (name, d)+  getTypeName (P.PositionedDeclaration _ _ d) = getTypeName d+  getTypeName _ = Nothing++identNames :: P.Module -> [(N.Ident, P.Declaration)]+identNames = nubOnFst . mapMaybe getDeclName . P.exportedDeclarations+  where+  getDeclName :: P.Declaration -> Maybe (P.Ident, P.Declaration)+  getDeclName d@(P.ValueDeclaration ident _ _ _)  = Just (ident, d)+  getDeclName d@(P.ExternDeclaration _ ident _ _) = Just (ident, d)+  getDeclName (P.PositionedDeclaration _ _ d) = getDeclName d+  getDeclName _ = Nothing++dctorNames :: P.Module -> [(N.ProperName, P.Declaration)]+dctorNames m = nubOnFst $ concatMap dctors dnames+  where+  getDataDeclName :: P.Declaration -> Maybe (N.ProperName, P.Declaration)+  getDataDeclName d@(P.DataDeclaration _ name _ _) = Just (name, d)+  getDataDeclName (P.PositionedDeclaration _ _ d) = getDataDeclName d+  getDataDeclName _ = Nothing++  dnames :: [(N.ProperName, P.Declaration)]+  dnames = (mapMaybe getDataDeclName onlyDataDecls)++  onlyDataDecls :: [P.Declaration]+  onlyDataDecls = (filter P.isDataDecl (P.exportedDeclarations m))++  dctors :: (N.ProperName, P.Declaration) -> [(N.ProperName, P.Declaration)]+  dctors (name, decl) = map (\n -> (n, decl)) (map fst (P.exportedDctors m name))++moduleNames :: [P.Module] -> [String]+moduleNames ms = nub [show moduleName | P.Module _ moduleName _ _ <- ms]++directivesFirst :: Completion -> Completion -> Ordering+directivesFirst (Completion _ d1 _) (Completion _ d2 _) = go d1 d2+  where+  go (':' : xs) (':' : ys) = compare xs ys+  go (':' : _) _ = LT+  go _ (':' : _) = GT+  go xs ys = compare xs ys
psci/Directive.hs view
@@ -15,65 +15,99 @@  module Directive where -import Data.List (nub, isPrefixOf)+import Data.Maybe (fromJust, listToMaybe)+import Data.List (isPrefixOf)+import Data.Tuple (swap) -data Directive-  = Help-  | Quit-  | Reset-  | Browse-  | Load-  | Type-  | Kind-  | Show-  deriving Eq+import Types  -- |--- Maps given directive to relating command strings.+-- List of all avaliable directives. ---commands :: Directive -> [String]-commands Help = ["?", "help"]-commands Quit = ["quit"]-commands Reset = ["reset"]-commands Browse = ["browse"]-commands Load = ["load", "module"]-commands Type = ["type"]-commands Kind = ["kind"]-commands Show = ["show"]+directives :: [Directive]+directives = map fst directiveStrings  -- |--- Tries to parse given string into a directive.+-- A mapping of directives to the different strings that can be used to invoke+-- them. ---parseDirective :: String -> Maybe Directive-parseDirective cmd =-  case filter (matches . snd) mapping of-    [directive] -> Just $ fst directive-    _ -> Nothing+directiveStrings :: [(Directive, [String])]+directiveStrings =+    [ (Help   , ["?", "help"])+    , (Quit   , ["quit"])+    , (Reset  , ["reset"])+    , (Browse , ["browse"])+    , (Load   , ["load", "module"])+    , (Type   , ["type"])+    , (Kind   , ["kind"])+    , (Show   , ["show"])+    ]++-- |+-- Like directiveStrings, but the other way around.+--+directiveStrings' :: [(String, Directive)]+directiveStrings' = concatMap go directiveStrings   where-  mapping :: [(Directive, [String])]-  mapping = zip directives (map commands directives)+  go (dir, strs) = map (\s -> (s, dir)) strs -  matches :: [String] -> Bool-  matches = any (cmd `isPrefixOf`)+-- |+-- List of all directive strings.+--+strings :: [String]+strings = concatMap snd directiveStrings  -- |+-- Returns all possible string representations of a directive.+--+stringsFor :: Directive -> [String]+stringsFor d = fromJust (lookup d directiveStrings)++-- |+-- Returns the default string representation of a directive.+--+stringFor :: Directive -> String+stringFor = head . stringsFor++-- |+-- Returns the list of directives which could be expanded from the string+-- argument, together with the string alias that matched.+--+directivesFor' :: String -> [(Directive, String)]+directivesFor' str = go directiveStrings'+  where+  go = map swap . filter ((str `isPrefixOf`) . fst)++directivesFor :: String -> [Directive]+directivesFor = map fst . directivesFor'++directiveStringsFor :: String -> [String]+directiveStringsFor = map snd . directivesFor'++parseDirective :: String -> Maybe Directive+parseDirective = listToMaybe . directivesFor++-- |+-- True if the given directive takes an argument, false otherwise.+hasArgument :: Directive -> Bool+hasArgument Help = False+hasArgument Quit = False+hasArgument Reset = False+hasArgument _ = True++-- | -- The help menu. -- help :: [(Directive, String, String)] help =   [ (Help,   "",         "Show this help menu")   , (Quit,   "",         "Quit PSCi")-  , (Reset,  "",         "Reset")-  , (Browse, "<module>", "Browse <module>")+  , (Reset,  "",         "Discard all imported modules and declared bindings")+  , (Browse, "<module>", "See all functions in <module>")   , (Load,   "<file>",   "Load <file> for importing")   , (Type,   "<expr>",   "Show the type of <expr>")   , (Kind,   "<type>",   "Show the kind of <type>")-  , (Show,   "import",   "Show imported modules")-  , (Show,   "loaded",   "Show loaded modules")+  , (Show,   "import",   "Show all imported modules")+  , (Show,   "loaded",   "Show all loaded modules")   ] --- |--- List of all avaliable directives.----directives :: [Directive]-directives = nub . map (\(dir, _, _) -> dir) $ help
− psci/Main.hs
@@ -1,702 +0,0 @@------------------------------------------------------------------------------------ Module      :  Main--- Copyright   :  (c) Phil Freeman 2013--- License     :  MIT------ Maintainer  :  Phil Freeman <paf31@cantab.net>--- Stability   :  experimental--- Portability :------ |--- PureScript Compiler Interactive.-----------------------------------------------------------------------------------{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DoAndIfThenElse #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RecordWildCards #-}--module Main where--import Data.Foldable (traverse_)-import Data.List (intercalate, isPrefixOf, nub, sortBy, sort)-import Data.Maybe (mapMaybe)-import Data.Traversable (traverse)-import Data.Version (showVersion)-import Data.Char (isSpace)-import qualified Data.Map as M--import Control.Applicative-import Control.Monad-import Control.Monad.Except (ExceptT(..), MonadError, runExceptT)-import Control.Monad.Reader (MonadReader, ReaderT, runReaderT)-import Control.Monad.Trans.Class-import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)-import Control.Monad.Trans.State.Strict-import qualified Control.Monad.Trans.State.Lazy as L--import Options.Applicative as Opts--import System.Console.Haskeline-import System.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)-import System.Exit-import System.FilePath (pathSeparator, takeDirectory, (</>), isPathSeparator)-import System.IO.Error (tryIOError)-import System.Process (readProcessWithExitCode)--import qualified Text.Parsec as Par (ParseError)--import qualified Language.PureScript as P-import qualified Language.PureScript.AST as D-import qualified Language.PureScript.Names as N-import qualified Paths_purescript as Paths--import qualified Commands as C-import qualified Directive as D-import Parser--data PSCiOptions = PSCiOptions-  { psciMultiLineMode  :: Bool-  , psciInputFile      :: [FilePath]-  , psciInputNodeFlags :: [String]-  }---- |--- The PSCI state.--- Holds a list of imported modules, loaded files, and partial let bindings.--- The let bindings are partial,--- because it makes more sense to apply the binding to the final evaluated expression.----data PSCiState = PSCiState-  { psciImportedFilenames   :: [FilePath]-  , 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---- |--- Updates the state to have more imported modules.----updateImportedFiles :: FilePath -> PSCiState -> PSCiState-updateImportedFiles filename st = st { psciImportedFilenames = filename : psciImportedFilenames st }---- |--- Updates the state to have more imported modules.----updateImportedModules :: C.ImportedModule -> PSCiState -> PSCiState-updateImportedModules im st = st { psciImportedModules = im : psciImportedModules st }---- |--- Updates the state to have more loaded files.----updateModules :: [(Either P.RebuildPolicy FilePath, P.Module)] -> PSCiState -> PSCiState-updateModules modules st = st { psciLoadedModules = psciLoadedModules st ++ modules }---- |--- Updates the state to have more let bindings.----updateLets :: [P.Declaration] -> PSCiState -> PSCiState-updateLets ds st = st { psciLetBindings = psciLetBindings st ++ ds }---- File helpers--- |--- Load the necessary modules.----defaultImports :: [C.ImportedModule]-defaultImports = [(P.ModuleName [P.ProperName "Prelude"], D.Implicit, Nothing)]---- |--- Locates the node executable.--- Checks for either @nodejs@ or @node@.----findNodeProcess :: IO (Maybe String)-findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names-  where names = ["nodejs", "node"]---- |--- Grabs the filename where the history is stored.----getHistoryFilename :: IO FilePath-getHistoryFilename = do-  home <- getHomeDirectory-  let filename = home </> ".purescript" </> "psci_history"-  mkdirp filename-  return filename---- |--- Loads a file for use with imports.----loadModule :: FilePath -> IO (Either String [P.Module])-loadModule filename = do-  content <- readFile filename-  return $ either (Left . show) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]---- |--- Load all modules, including the Prelude----loadAllModules :: [FilePath] -> IO (Either Par.ParseError [(Either P.RebuildPolicy FilePath, P.Module)])-loadAllModules files = do-  filesAndContent <- forM files $ \filename -> do-    content <- readFile filename-    return (Right filename, content)-  return $ P.parseModulesFromFiles (either (const "") id) $ (Left P.RebuildNever, P.prelude) : filesAndContent---- |--- Load all modules, updating the application state----loadAllImportedModules :: PSCI ()-loadAllImportedModules = do-  files <- PSCI . lift $ fmap psciImportedFilenames get-  modulesOrFirstError <- psciIO $ loadAllModules files-  case modulesOrFirstError of-    Left err -> psciIO $ print err-    Right modules -> PSCI . lift . modify $ \st -> st { psciLoadedModules = modules }---- |--- Expands tilde in path.----expandTilde :: FilePath -> IO FilePath-expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory-expandTilde p = return p--- Messages---- |--- The help message.----helpMessage :: String-helpMessage = "The following commands are available:\n\n    " ++-  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.----prologueMessage :: String-prologueMessage = intercalate "\n"-  [ " ____                 ____            _       _   "-  , "|  _ \\ _   _ _ __ ___/ ___|  ___ _ __(_)_ __ | |_ "-  , "| |_) | | | | '__/ _ \\___ \\ / __| '__| | '_ \\| __|"-  , "|  __/| |_| | | |  __/___) | (__| |  | | |_) | |_ "-  , "|_|    \\__,_|_|  \\___|____/ \\___|_|  |_| .__/ \\__|"-  , "                                       |_|        "-  , ""-  , ":? shows help"-  ]---- |--- The quit message.----quitMessage :: String-quitMessage = "See ya!"---- Haskeline completions--data CompletionContext = Command String | FilePath String | Module | Identifier-                       | Type | Fixed [String] | Multiple [CompletionContext]-                         deriving (Show)---- |--- Decide what kind of completion we need based on input.-completionContext :: String -> String -> Maybe CompletionContext-completionContext cmd@"" _ = Just $ Multiple [Command cmd, Identifier]-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---- |--- Loads module, function, and file completions.----completion :: CompletionFunc (StateT PSCiState IO)-completion = completeWordWithPrev Nothing " \t\n\r" findCompletions-  where-  findCompletions :: String -> String -> StateT PSCiState IO [Completion]-  findCompletions prev word = do-    let ctx = completionContext ((dropWhile isSpace (reverse prev)) ++ word) word-    completions <- case ctx of-      Nothing -> return []-      (Just c) -> (mapMaybe $ either (\cand -> if word `isPrefixOf` cand-                                               then Just $ simpleCompletion cand-                                               else Nothing) Just)-                  <$> getCompletion c-    return $ sortBy sorter completions--  getCompletion :: CompletionContext -> StateT PSCiState IO [Either String Completion]-  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--  getModuleNames :: StateT PSCiState IO [String]-  getModuleNames = moduleNames <$> getLoadedModules--  mapLoadedModulesAndQualify :: (Show a) => (P.Module -> [a]) -> StateT PSCiState IO [String]-  mapLoadedModulesAndQualify f = do-    ms <- getLoadedModules-    q <- sequence [qualifyIfNeeded m (f m) | m <- ms]-    return $ concat q--  getIdentNames :: StateT PSCiState IO [String]-  getIdentNames = mapLoadedModulesAndQualify identNames--  getDctorNames :: StateT PSCiState IO [String]-  getDctorNames = mapLoadedModulesAndQualify dctorNames--  getTypeNames :: StateT PSCiState IO [String]-  getTypeNames = mapLoadedModulesAndQualify typeDecls--  qualifyIfNeeded :: (Show a) => P.Module -> [a] -> StateT PSCiState IO [String]-  qualifyIfNeeded m decls = do-    let name = P.getModuleName m-    imported <- psciImportedModuleNames <$> get-    let qualified = map (P.Qualified $ Just name) decls-    if name `elem` imported then-        return $ map show $ qualified ++ (map (P.Qualified Nothing) decls)-    else-        return $ map show qualified--  typeDecls :: P.Module -> [N.ProperName]-  typeDecls m = mapMaybe getTypeName $ filter P.isDataDecl (P.exportedDeclarations m)-      where getTypeName :: P.Declaration -> Maybe N.ProperName-            getTypeName (P.TypeSynonymDeclaration name _ _) = Just name-            getTypeName (P.DataDeclaration _ name _ _) = Just name-            getTypeName (P.PositionedDeclaration _ _ d) = getTypeName d-            getTypeName _ = Nothing--  identNames :: P.Module -> [N.Ident]-  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-          getDeclName exts (P.PositionedDeclaration _ _ d) = getDeclName exts d-          getDeclName _ _ = Nothing--  dctorNames :: P.Module -> [N.ProperName]-  dctorNames m = nub $ concat $ map (P.exportedDctors m) dnames-    where getDataDeclName :: P.Declaration -> Maybe N.ProperName-          getDataDeclName (P.DataDeclaration _ name _ _) = Just name-          getDataDeclName (P.PositionedDeclaration _ _ d) = getDataDeclName d-          getDataDeclName _ = Nothing--          dnames :: [N.ProperName]-          dnames = (mapMaybe getDataDeclName onlyDataDecls)--          onlyDataDecls :: [P.Declaration]-          onlyDataDecls = (filter P.isDataDecl (P.exportedDeclarations m))--  moduleNames :: [P.Module] -> [String]-  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---- Compilation---- | Compilation options.----options :: P.Options P.Make-options = P.Options False False False Nothing False False False P.MakeOptions---- |--- PSCI monad----newtype PSCI a = PSCI { runPSCI :: InputT (StateT PSCiState IO) a } deriving (Functor, Applicative, Monad)--psciIO :: IO a -> PSCI a-psciIO io = PSCI . lift $ lift io--newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (ExceptT String IO) a }-  deriving (Functor, Applicative, Monad, MonadError String, MonadReader (P.Options P.Make))--runMake :: Make a -> IO (Either String a)-runMake = runExceptT . flip runReaderT options . unMake--makeIO :: IO a -> Make a-makeIO = Make . lift . ExceptT . fmap (either (Left . show) Right) . tryIOError--instance P.MonadMake Make where-  getTimestamp path = makeIO $ do-    exists <- doesFileExist path-    traverse (const $ getModificationTime path) $ guard exists-  readTextFile path = makeIO $ readFile path-  writeTextFile path text = makeIO $ do-    mkdirp path-    writeFile path text-  progress s = unless (s == "Compiling $PSCI") $ makeIO . putStrLn $ s--mkdirp :: FilePath -> IO ()-mkdirp = createDirectoryIfMissing True . takeDirectory---- |--- Makes a volatile module to execute the current expression.----createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module-createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =-  let-    moduleName = P.ModuleName [P.ProperName "$PSCI"]-    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")))-    itDecl = P.ValueDeclaration (P.Ident "it") P.Value [] $ Right val-    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----- |--- 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{psciImportedModules = imports} typ =-  let-    moduleName = P.ModuleName [P.ProperName "$PSCI"]-    itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ-  in-    P.Module [] moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing---- |--- Makes a volatile module to execute the current imports.----createTemporaryModuleForImports :: PSCiState -> P.Module-createTemporaryModuleForImports PSCiState{psciImportedModules = imports} =-  let-    moduleName = P.ModuleName [P.ProperName "$PSCI"]-  in-    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"--indexFile :: FilePath-indexFile = ".psci_modules" ++ pathSeparator : "index.js"---- |--- Takes a value declaration and evaluates it with the current state.----handleDeclaration :: P.Expr -> PSCI ()-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 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 list of declarations and updates the environment, then run a make. If the declaration fails,--- restore the original environment.----handleDecls :: [P.Declaration] -> PSCI ()-handleDecls ds = do-  st <- PSCI $ lift get-  let st' = updateLets ds st-  let m = createTemporaryModule False st' (P.ObjectLiteral [])-  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st' ++ [(Left P.RebuildAlways, m)]) []-  case e of-    Left err -> PSCI $ outputStrLn err-    Right _ -> PSCI $ lift (put st')---- |--- Show actual loaded modules in psci.----handleShowLoadedModules :: PSCI ()-handleShowLoadedModules = do-  PSCiState { psciLoadedModules = loadedModules } <- PSCI $ lift get-  psciIO $ readModules loadedModules >>= putStrLn-  return ()-  where readModules = return . unlines . sort . nub . map toModuleName-        toModuleName =  N.runModuleName . (\ (D.Module _ mdName _ _) -> mdName) . snd---- |--- Show the imported modules in psci.----handleShowImportedModules :: PSCI ()-handleShowImportedModules = do-  PSCiState { psciImportedModules = importedModules } <- PSCI $ lift get-  psciIO $ showModules importedModules >>= putStrLn-  return ()-  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 :: 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-     Left err -> PSCI $ outputStrLn err-     Right _  -> do-       PSCI $ lift $ put st-       return ()---- |--- Takes a value and prints its type----handleTypeOf :: P.Expr -> PSCI ()-handleTypeOf val = do-  st <- PSCI $ lift get-  let m = createTemporaryModule False st val-  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []-  case e of-    Left err -> PSCI $ outputStrLn err-    Right env' ->-      case M.lookup (P.ModuleName [P.ProperName "$PSCI"], P.Ident "it") (P.names env') of-        Just (ty, _, _) -> PSCI . outputStrLn . P.prettyPrintType $ ty-        Nothing -> PSCI $ outputStrLn "Could not find type"---- |--- Pretty print a module's signatures----printModuleSignatures :: P.ModuleName -> P.Environment -> PSCI ()-printModuleSignatures moduleName env =-  PSCI $ let namesEnv = P.names env-             moduleNamesIdent = (filter ((== moduleName) . fst) . M.keys) namesEnv-             in case moduleNamesIdent of-                  [] -> outputStrLn $ "This module '"++ P.runModuleName moduleName ++"' does not export functions."-                  _ -> ( outputStrLn-                       . unlines-                       . sort-                       . map (showType . findType namesEnv)) moduleNamesIdent-  where findType :: M.Map (P.ModuleName, P.Ident) (P.Type, P.NameKind, P.NameVisibility) -> (P.ModuleName, P.Ident) -> (P.Ident, Maybe (P.Type, P.NameKind, P.NameVisibility))-        findType envNames m@(_, mIdent) = (mIdent, M.lookup m envNames)-        showType :: (P.Ident, Maybe (P.Type, P.NameKind, P.NameVisibility)) -> String-        showType (mIdent, Just (mType, _, _)) = show mIdent ++ " :: " ++ P.prettyPrintType mType-        showType _ = error "The impossible happened in printModuleSignatures."---- |--- Browse a module and displays its signature (if module exists).----handleBrowse :: P.ModuleName -> PSCI ()-handleBrowse moduleName = do-  st <- PSCI $ lift get-  let loadedModules = psciLoadedModules st-  env <- psciIO . runMake $ P.make modulesDir loadedModules []-  case env of-    Left err -> PSCI $ outputStrLn err-    Right env' ->-      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'---- |--- Takes a value and prints its kind----handleKindOf :: P.Type -> PSCI ()-handleKindOf typ = do-  st <- PSCI $ lift get-  let m = createTemporaryModuleForKind st typ-      mName = P.ModuleName [P.ProperName "$PSCI"]-  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []-  case e of-    Left err -> PSCI $ outputStrLn err-    Right env' ->-      case M.lookup (P.Qualified (Just mName) $ P.ProperName "IT") (P.typeSynonyms env') of-        Just (_, typ') -> do-          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.prettyPrintMultipleErrors False $ errStack-            Right (kind, _) -> PSCI . outputStrLn . P.prettyPrintKind $ kind-        Nothing -> PSCI $ outputStrLn "Could not find kind"---- Commands---- |--- Parses the input and returns either a Metacommand or an expression.----getCommand :: Bool -> InputT (StateT PSCiState IO) (Either String (Maybe C.Command))-getCommand singleLineMode = do-  firstLine <- getInputLine "> "-  case firstLine of-    Nothing -> return (Right Nothing)-    Just "" -> return (Right Nothing)-    Just s | singleLineMode || head s == ':' -> return . either Left (Right . Just) $ parseCommand s-    Just s -> either Left (Right . Just) . parseCommand <$> go [s]-  where-    go :: [String] -> InputT (StateT PSCiState IO) String-    go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine "  "---- |--- Performs an action for each meta-command given, and also for expressions..----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-    PSCI . lift $ modify (updateImportedFiles absPath)-    m <- psciIO $ loadModule absPath-    case m of-      Left err -> PSCI $ outputStrLn err-      Right mods -> PSCI . lift $ modify (updateModules (map ((,) (Right absPath)) mods))-  else-    PSCI . outputStrLn $ "Couldn't locate: " ++ filePath-handleCommand C.Reset = do-  files <- psciImportedFilenames <$> PSCI (lift get)-  PSCI . lift . modify $ \st -> st-    { psciImportedFilenames   = files-    , psciImportedModules     = defaultImports-    , psciLetBindings         = []-    }-  loadAllImportedModules-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 [C.Command])-loadUserConfig = do-  configFile <- (</> ".psci") <$> getCurrentDirectory-  exists <- doesFileExist configFile-  if exists-  then do-    ls <- lines <$> readFile configFile-    case mapM parseCommand ls of-      Left err -> print err >> exitFailure-      Right cs -> return $ Just cs-  else-    return Nothing---- |--- The PSCI main loop.----loop :: PSCiOptions -> IO ()-loop PSCiOptions{..} = do-  config <- loadUserConfig-  modulesOrFirstError <- loadAllModules psciInputFile-  case modulesOrFirstError of-    Left err -> print err >> exitFailure-    Right modules -> do-      historyFilename <- getHistoryFilename-      let settings = defaultSettings { historyFile = Just historyFilename }-      flip evalStateT (PSCiState psciInputFile defaultImports modules [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do-        outputStrLn prologueMessage-        traverse_ (mapM_ (runPSCI . handleCommand)) config-        go-      where-        go :: InputT (StateT PSCiState IO) ()-        go = do-          c <- getCommand (not psciMultiLineMode)-          case c of-            Left err -> outputStrLn err >> go-            Right Nothing -> go-            Right (Just C.Quit) -> outputStrLn quitMessage-            Right (Just c') -> runPSCI (loadAllImportedModules >> handleCommand c') >> go--multiLineMode :: Parser Bool-multiLineMode = switch $-     long "multi-line-mode"-  <> short 'm'-  <> Opts.help "Run in multi-line mode (use ^D to terminate commands)"--inputFile :: Parser FilePath-inputFile = strArgument $-     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-  where-  opts        = info (version <*> helper <*> psciOptions) infoModList-  infoModList = fullDesc <> headerInfo <> footerInfo-  headerInfo  = header   "psci - Interactive mode for PureScript"-  footerInfo  = footer $ "psci " ++ showVersion Paths.version--  version :: Parser (a -> a)-  version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> Opts.help "Show the version number" <> hidden
+ psci/PSCi.hs view
@@ -0,0 +1,543 @@+-----------------------------------------------------------------------------+--+-- Module      :  PSCi+-- Copyright   :  (c) Phil Freeman 2013+-- License     :  MIT+--+-- Maintainer  :  Phil Freeman <paf31@cantab.net>+-- Stability   :  experimental+-- Portability :+--+-- |+-- PureScript Compiler Interactive.+--+-----------------------------------------------------------------------------++{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RecordWildCards #-}++module PSCi where++import Data.Foldable (traverse_)+import Data.List (intercalate, nub, sort)+import Data.Traversable (traverse)+import Data.Version (showVersion)+import qualified Data.Map as M++import Control.Applicative+import Control.Monad+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Error.Class (throwError)+import Control.Monad.Except (ExceptT(..), MonadError, runExceptT)+import Control.Monad.Reader (MonadReader, ReaderT, runReaderT)+import Control.Monad.Trans.Class+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)+import Control.Monad.Trans.State.Strict+import qualified Control.Monad.Trans.State.Lazy as L++import Options.Applicative as Opts++import System.Console.Haskeline+import System.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)+import System.Exit+import System.FilePath (pathSeparator, takeDirectory, (</>), isPathSeparator)+import System.IO.Error (tryIOError)+import System.Process (readProcessWithExitCode)++import qualified Text.Parsec as Par (ParseError)++import qualified Language.PureScript as P+import qualified Language.PureScript.Names as N+import qualified Paths_purescript as Paths++import qualified Directive as D+import Parser (parseCommand)+import Completion (completion)+import Types+++-- File helpers+-- |+-- Load the necessary modules.+--+defaultImports :: [ImportedModule]+defaultImports = [(P.ModuleName [P.ProperName "Prelude"], P.Implicit, Nothing)]++-- |+-- Locates the node executable.+-- Checks for either @nodejs@ or @node@.+--+findNodeProcess :: IO (Maybe String)+findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names+  where names = ["nodejs", "node"]++-- |+-- Grabs the filename where the history is stored.+--+getHistoryFilename :: IO FilePath+getHistoryFilename = do+  home <- getHomeDirectory+  let filename = home </> ".purescript" </> "psci_history"+  mkdirp filename+  return filename++-- |+-- Loads a file for use with imports.+--+loadModule :: FilePath -> IO (Either String [P.Module])+loadModule filename = do+  content <- readFile filename+  return $ either (Left . show) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]++-- |+-- Load all modules, including the Prelude+--+loadAllModules :: [FilePath] -> IO (Either Par.ParseError [(Either P.RebuildPolicy FilePath, P.Module)])+loadAllModules files = do+  filesAndContent <- forM files $ \filename -> do+    content <- readFile filename+    return (Right filename, content)+  return $ P.parseModulesFromFiles (either (const "") id) $ (Left P.RebuildNever, P.prelude) : filesAndContent++-- |+-- Load all modules, updating the application state+--+loadAllImportedModules :: PSCI ()+loadAllImportedModules = do+  files <- PSCI . lift $ fmap psciImportedFilenames get+  modulesOrFirstError <- psciIO $ loadAllModules files+  case modulesOrFirstError of+    Left err -> psciIO $ print err+    Right modules -> PSCI . lift . modify $ \st -> st { psciLoadedModules = modules }++-- |+-- Expands tilde in path.+--+expandTilde :: FilePath -> IO FilePath+expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory+expandTilde p = return p+-- Messages++-- |+-- The help message.+--+helpMessage :: String+helpMessage = "The following commands are available:\n\n    " +++  intercalate "\n    " (map line D.help) +++  "\n\n" ++ extraHelp+  where+  line :: (Directive, String, String) -> String+  line (dir, arg, desc) =+    let cmd = ':' : D.stringFor dir+    in intercalate " "+        [ cmd+        , replicate (11 - length cmd) ' '+        , arg+        , replicate (11 - length arg) ' '+        , desc+        ]++  extraHelp =+    "Further information is available on the PureScript wiki:\n" +++    " --> https://github.com/purescript/purescript/wiki/psci"+++-- |+-- The welcome prologue.+--+prologueMessage :: String+prologueMessage = intercalate "\n"+  [ " ____                 ____            _       _   "+  , "|  _ \\ _   _ _ __ ___/ ___|  ___ _ __(_)_ __ | |_ "+  , "| |_) | | | | '__/ _ \\___ \\ / __| '__| | '_ \\| __|"+  , "|  __/| |_| | | |  __/___) | (__| |  | | |_) | |_ "+  , "|_|    \\__,_|_|  \\___|____/ \\___|_|  |_| .__/ \\__|"+  , "                                       |_|        "+  , ""+  , ":? shows help"+  ]++-- |+-- The quit message.+--+quitMessage :: String+quitMessage = "See ya!"+++-- Compilation++-- | Compilation options.+--+options :: P.Options P.Make+options = P.Options False False False Nothing False False False P.MakeOptions++-- |+-- PSCI monad+--+newtype PSCI a = PSCI { runPSCI :: InputT (StateT PSCiState IO) a } deriving (Functor, Applicative, Monad)++psciIO :: IO a -> PSCI a+psciIO io = PSCI . lift $ lift io++newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (ExceptT P.MultipleErrors IO) a }+  deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadReader (P.Options P.Make))++runMake :: Make a -> IO (Either P.MultipleErrors a)+runMake = runExceptT . flip runReaderT options . unMake++makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a+makeIO f io = do+  e <- liftIO $ tryIOError io+  either (throwError . P.errorMessage . f) return e++instance P.MonadMake Make where+  getTimestamp path = makeIO (const (P.CannotGetFileInfo path)) $ do+    exists <- doesFileExist path+    traverse (const $ getModificationTime path) $ guard exists+  readTextFile path = makeIO (const (P.CannotReadFile path)) $ readFile path+  writeTextFile path text = makeIO (const (P.CannotWriteFile path)) $ do+    mkdirp path+    writeFile path text+  progress s = unless (s == "Compiling $PSCI") $ liftIO . putStrLn $ s++mkdirp :: FilePath -> IO ()+mkdirp = createDirectoryIfMissing True . takeDirectory++-- |+-- Makes a volatile module to execute the current expression.+--+createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module+createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =+  let+    moduleName = P.ModuleName [P.ProperName "$PSCI"]+    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")))+    itDecl = P.ValueDeclaration (P.Ident "it") P.Value [] $ Right val+    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+++-- |+-- 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{psciImportedModules = imports} typ =+  let+    moduleName = P.ModuleName [P.ProperName "$PSCI"]+    itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ+  in+    P.Module [] moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing++-- |+-- Makes a volatile module to execute the current imports.+--+createTemporaryModuleForImports :: PSCiState -> P.Module+createTemporaryModuleForImports PSCiState{psciImportedModules = imports} =+  let+    moduleName = P.ModuleName [P.ProperName "$PSCI"]+  in+    P.Module [] moduleName (importDecl `map` imports) Nothing++importDecl :: ImportedModule -> P.Declaration+importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ++modulesDir :: FilePath+modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"++indexFile :: FilePath+indexFile = ".psci_modules" ++ pathSeparator : "index.js"++-- |+-- Takes a value declaration and evaluates it with the current state.+--+handleDeclaration :: P.Expr -> PSCI ()+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 errs -> printErrors errs+    Right _ -> do+      psciIO $ writeFile indexFile "require('$PSCI').main();"+      process <- psciIO findNodeProcess+      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 list of declarations and updates the environment, then run a make. If the declaration fails,+-- restore the original environment.+--+handleDecls :: [P.Declaration] -> PSCI ()+handleDecls ds = do+  st <- PSCI $ lift get+  let st' = updateLets ds st+  let m = createTemporaryModule False st' (P.ObjectLiteral [])+  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st' ++ [(Left P.RebuildAlways, m)]) []+  case e of+    Left err -> printErrors err+    Right _ -> PSCI $ lift (put st')++-- |+-- Show actual loaded modules in psci.+--+handleShowLoadedModules :: PSCI ()+handleShowLoadedModules = do+  PSCiState { psciLoadedModules = loadedModules } <- PSCI $ lift get+  psciIO $ readModules loadedModules >>= putStrLn+  return ()+  where readModules = return . unlines . sort . nub . map toModuleName+        toModuleName =  N.runModuleName . (\ (P.Module _ mdName _ _) -> mdName) . snd++-- |+-- Show the imported modules in psci.+--+handleShowImportedModules :: PSCI ()+handleShowImportedModules = do+  PSCiState { psciImportedModules = importedModules } <- PSCI $ lift get+  psciIO $ showModules importedModules >>= putStrLn+  return ()+  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 P.Implicit = ""+  showDeclType (P.Explicit refs) = refsList refs+  showDeclType (P.Hiding refs) = "hiding " ++ refsList refs+  refsList refs = "(" ++ commaList (map showRef refs) ++ ")"++  showRef :: P.DeclarationRef -> String+  showRef (P.TypeRef pn dctors) = show pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"+  showRef (P.ValueRef ident) = show ident+  showRef (P.TypeClassRef pn) = show pn+  showRef (P.TypeInstanceRef ident) = show ident+  showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref++  commaList :: [String] -> String+  commaList = intercalate ", "++-- |+-- Imports a module, preserving the initial state on failure.+--+handleImport :: 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+     Left errs -> printErrors errs+     Right _  -> do+       PSCI $ lift $ put st+       return ()++-- |+-- Takes a value and prints its type+--+handleTypeOf :: P.Expr -> PSCI ()+handleTypeOf val = do+  st <- PSCI $ lift get+  let m = createTemporaryModule False st val+  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []+  case e of+    Left errs -> printErrors errs+    Right env' ->+      case M.lookup (P.ModuleName [P.ProperName "$PSCI"], P.Ident "it") (P.names env') of+        Just (ty, _, _) -> PSCI . outputStrLn . P.prettyPrintType $ ty+        Nothing -> PSCI $ outputStrLn "Could not find type"++-- |+-- Pretty print a module's signatures+--+printModuleSignatures :: P.ModuleName -> P.Environment -> PSCI ()+printModuleSignatures moduleName env =+  PSCI $ let namesEnv = P.names env+             moduleNamesIdent = (filter ((== moduleName) . fst) . M.keys) namesEnv+             in case moduleNamesIdent of+                  [] -> outputStrLn $ "This module '"++ P.runModuleName moduleName ++"' does not export functions."+                  _ -> ( outputStrLn+                       . unlines+                       . sort+                       . map (showType . findType namesEnv)) moduleNamesIdent+  where findType :: M.Map (P.ModuleName, P.Ident) (P.Type, P.NameKind, P.NameVisibility) -> (P.ModuleName, P.Ident) -> (P.Ident, Maybe (P.Type, P.NameKind, P.NameVisibility))+        findType envNames m@(_, mIdent) = (mIdent, M.lookup m envNames)+        showType :: (P.Ident, Maybe (P.Type, P.NameKind, P.NameVisibility)) -> String+        showType (mIdent, Just (mType, _, _)) = show mIdent ++ " :: " ++ P.prettyPrintType mType+        showType _ = error "The impossible happened in printModuleSignatures."++-- |+-- Browse a module and displays its signature (if module exists).+--+handleBrowse :: P.ModuleName -> PSCI ()+handleBrowse moduleName = do+  st <- PSCI $ lift get+  let loadedModules = psciLoadedModules st+  env <- psciIO . runMake $ P.make modulesDir loadedModules []+  case env of+    Left errs -> printErrors errs+    Right env' ->+      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'++-- | Pretty-print errors+printErrors :: P.MultipleErrors -> PSCI ()+printErrors = PSCI . outputStrLn . P.prettyPrintMultipleErrors False++-- |+-- Takes a value and prints its kind+--+handleKindOf :: P.Type -> PSCI ()+handleKindOf typ = do+  st <- PSCI $ lift get+  let m = createTemporaryModuleForKind st typ+      mName = P.ModuleName [P.ProperName "$PSCI"]+  e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []+  case e of+    Left errs -> printErrors errs+    Right env' ->+      case M.lookup (P.Qualified (Just mName) $ P.ProperName "IT") (P.typeSynonyms env') of+        Just (_, typ') -> do+          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.prettyPrintMultipleErrors False $ errStack+            Right (kind, _) -> PSCI . outputStrLn . P.prettyPrintKind $ kind+        Nothing -> PSCI $ outputStrLn "Could not find kind"++-- Commands++-- |+-- Parses the input and returns either a Metacommand, or an error as a string.+--+getCommand :: Bool -> InputT (StateT PSCiState IO) (Either String (Maybe Command))+getCommand singleLineMode = do+  firstLine <- getInputLine "> "+  case firstLine of+    Nothing -> return (Right Nothing)+    Just "" -> return (Right Nothing)+    Just s | singleLineMode || head s == ':' -> return . either Left (Right . Just) $ parseCommand s+    Just s -> either Left (Right . Just) . parseCommand <$> go [s]+  where+    go :: [String] -> InputT (StateT PSCiState IO) String+    go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine "  "++-- |+-- Performs an action for each meta-command given, and also for expressions.+--+handleCommand :: Command -> PSCI ()+handleCommand (Expression val) = handleDeclaration val+handleCommand ShowHelp = PSCI $ outputStrLn helpMessage+handleCommand (Import im) = handleImport im+handleCommand (Decls l) = handleDecls l+handleCommand (LoadFile filePath) = do+  absPath <- psciIO $ expandTilde filePath+  exists <- psciIO $ doesFileExist absPath+  if exists then do+    PSCI . lift $ modify (updateImportedFiles absPath)+    m <- psciIO $ loadModule absPath+    case m of+      Left err -> PSCI $ outputStrLn err+      Right mods -> PSCI . lift $ modify (updateModules (map ((,) (Right absPath)) mods))+  else+    PSCI . outputStrLn $ "Couldn't locate: " ++ filePath+handleCommand ResetState = do+  files <- psciImportedFilenames <$> PSCI (lift get)+  PSCI . lift . modify $ \st -> st+    { psciImportedFilenames   = files+    , psciImportedModules     = defaultImports+    , psciLetBindings         = []+    }+  loadAllImportedModules+handleCommand (TypeOf val) = handleTypeOf val+handleCommand (KindOf typ) = handleKindOf typ+handleCommand (BrowseModule moduleName) = handleBrowse moduleName+handleCommand (ShowInfo QueryLoaded) = handleShowLoadedModules+handleCommand (ShowInfo QueryImport) = handleShowImportedModules+handleCommand QuitPSCi = error "`handleCommand QuitPSCi` was called. This is a bug."++loadUserConfig :: IO (Maybe [Command])+loadUserConfig = do+  configFile <- (</> ".psci") <$> getCurrentDirectory+  exists <- doesFileExist configFile+  if exists+  then do+    ls <- lines <$> readFile configFile+    case mapM parseCommand ls of+      Left err -> print err >> exitFailure+      Right cs -> return $ Just cs+  else+    return Nothing++-- |+-- The PSCI main loop.+--+loop :: PSCiOptions -> IO ()+loop PSCiOptions{..} = do+  config <- loadUserConfig+  modulesOrFirstError <- loadAllModules psciInputFile+  case modulesOrFirstError of+    Left err -> print err >> exitFailure+    Right modules -> do+      historyFilename <- getHistoryFilename+      let settings = defaultSettings { historyFile = Just historyFilename }+      flip evalStateT (PSCiState psciInputFile defaultImports modules [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do+        outputStrLn prologueMessage+        traverse_ (mapM_ (runPSCI . handleCommand)) config+        go+      where+        go :: InputT (StateT PSCiState IO) ()+        go = do+          c <- getCommand (not psciMultiLineMode)+          case c of+            Left err -> outputStrLn err >> go+            Right Nothing -> go+            Right (Just QuitPSCi) -> outputStrLn quitMessage+            Right (Just c') -> runPSCI (loadAllImportedModules >> handleCommand c') >> go++multiLineMode :: Parser Bool+multiLineMode = switch $+     long "multi-line-mode"+  <> short 'm'+  <> Opts.help "Run in multi-line mode (use ^D to terminate commands)"++inputFile :: Parser FilePath+inputFile = strArgument $+     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++runPSCi :: IO ()+runPSCi = execParser opts >>= loop+  where+  opts        = info (version <*> helper <*> psciOptions) infoModList+  infoModList = fullDesc <> headerInfo <> footerInfo+  headerInfo  = header   "psci - Interactive mode for PureScript"+  footerInfo  = footer $ "psci " ++ showVersion Paths.version++  version :: Parser (a -> a)+  version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> Opts.help "Show the version number" <> hidden
psci/Parser.hs view
@@ -19,22 +19,23 @@  import Prelude hiding (lex) -import qualified Commands as C-import qualified Directive as D- import Data.Char (isSpace)+import Data.List (intercalate)  import Control.Applicative hiding (many)  import Text.Parsec hiding ((<|>))  import qualified Language.PureScript as P-import qualified Language.PureScript.Parser.Common as C (mark, same)+import Language.PureScript.Parser.Common (mark, same) +import qualified Directive as D+import Types+ -- | -- Parses PSCI metacommands or expressions input from the user. ---parseCommand :: String -> Either String C.Command+parseCommand :: String -> Either String Command parseCommand cmdString =   case cmdString of     (':' : cmd) -> parseDirective cmd@@ -45,7 +46,7 @@   ts <- P.lex "" s   P.runTokenParser "" (p <* eof) ts -psciCommand :: P.TokenParser C.Command+psciCommand :: P.TokenParser Command psciCommand = choice (map try parsers)   where   parsers =@@ -64,25 +65,31 @@ trimEnd :: String -> String trimEnd = reverse . trimStart . reverse -parseDirective :: String -> Either String C.Command+parseDirective :: String -> Either String 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+  case D.directivesFor' dstr of+    [(d, _)] -> commandFor d+    []       -> Left "Unrecognized directive. Type :? for help."+    ds       -> Left ("Ambiguous directive. Possible matches: " +++                  intercalate ", " (map snd ds) ++ ". Type :? for help.")+  where+  (dstr, arg) = break isSpace cmd +  commandFor d = case d of+    Help   -> return ShowHelp+    Quit   -> return QuitPSCi+    Reset  -> return ResetState+    Browse -> BrowseModule <$> parseRest P.moduleName arg+    Load   -> return $ LoadFile (trim arg)+    Show   -> ShowInfo <$> parseReplQuery' (trim arg)+    Type   -> TypeOf <$> parseRest P.parseValue arg+    Kind   -> KindOf <$> parseRest P.parseType arg+ -- | -- Parses expressions entered at the PSCI repl. ---psciExpression :: P.TokenParser C.Command-psciExpression = C.Expression <$> P.parseValue+psciExpression :: P.TokenParser Command+psciExpression = Expression <$> P.parseValue  -- | -- PSCI version of @let@.@@ -90,21 +97,21 @@ -- 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)+psciLet :: P.TokenParser Command+psciLet = Decls <$> (P.reserved "let" *> P.indented *> manyDecls)   where   manyDecls :: P.TokenParser [P.Declaration]-  manyDecls = C.mark (many1 (C.same *> P.parseLocalDeclaration))+  manyDecls = mark (many1 (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'+psciImport :: P.TokenParser Command+psciImport = 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+psciOtherDeclaration :: P.TokenParser Command+psciOtherDeclaration = Decls . (:[]) <$> do   decl <- discardPositionInfo <$> P.parseDeclaration   if acceptable decl     then return decl@@ -123,3 +130,10 @@ acceptable (P.TypeClassDeclaration _ _ _ _) = True acceptable (P.TypeInstanceDeclaration _ _ _ _ _) = True acceptable _ = False++parseReplQuery' :: String -> Either String ReplQuery+parseReplQuery' str =+  case parseReplQuery str of+    Nothing -> Left ("Don't know how to show " ++ str ++ ". Try one of: " +++                      intercalate ", " replQueryStrings ++ ".")+    Just query -> Right query
+ psci/Types.hs view
@@ -0,0 +1,167 @@+-----------------------------------------------------------------------------+--+-- Module      :  Types+-- Copyright   :  (c) Phil Freeman 2014+-- License     :  MIT+--+-- Maintainer  :  Phil Freeman <paf31@cantab.net>+-- Stability   :  experimental+-- Portability :+--+-- |+-- Type declarations and associated basic functions for PSCI.+--+-----------------------------------------------------------------------------++module Types where++import qualified Language.PureScript as P++data PSCiOptions = PSCiOptions+  { psciMultiLineMode  :: Bool+  , psciInputFile      :: [FilePath]+  , psciInputNodeFlags :: [String]+  }++-- |+-- The PSCI state.+-- Holds a list of imported modules, loaded files, and partial let bindings.+-- The let bindings are partial,+-- because it makes more sense to apply the binding to the final evaluated expression.+--+data PSCiState = PSCiState+  { psciImportedFilenames   :: [FilePath]+  , psciImportedModules     :: [ImportedModule]+  , psciLoadedModules       :: [(Either P.RebuildPolicy FilePath, P.Module)]+  , psciLetBindings         :: [P.Declaration]+  , psciNodeFlags           :: [String]+  }++-- | All of the data that is contained by an ImportDeclaration in the AST.+-- That is:+--+-- * 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 = (P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)++psciImportedModuleNames :: PSCiState -> [P.ModuleName]+psciImportedModuleNames (PSCiState{psciImportedModules = is}) =+  map (\(mn, _, _) -> mn) is++allImportsOf :: P.Module -> PSCiState -> [ImportedModule]+allImportsOf m (PSCiState{psciImportedModules = is}) =+  filter isImportOfThis is+  where+  name = P.getModuleName m+  isImportOfThis (name', _, _) = name == name'++-- State helpers++-- |+-- Updates the state to have more imported modules.+--+updateImportedFiles :: FilePath -> PSCiState -> PSCiState+updateImportedFiles filename st = st { psciImportedFilenames = filename : psciImportedFilenames st }++-- |+-- Updates the state to have more imported modules.+--+updateImportedModules :: ImportedModule -> PSCiState -> PSCiState+updateImportedModules im st = st { psciImportedModules = im : psciImportedModules st }++-- |+-- Updates the state to have more loaded files.+--+updateModules :: [(Either P.RebuildPolicy FilePath, P.Module)] -> PSCiState -> PSCiState+updateModules modules st = st { psciLoadedModules = psciLoadedModules st ++ modules }++-- |+-- Updates the state to have more let bindings.+--+updateLets :: [P.Declaration] -> PSCiState -> PSCiState+updateLets ds st = st { psciLetBindings = psciLetBindings st ++ ds }++-- |+-- Valid Meta-commands for PSCI+--+data Command+  -- |+  -- A purescript expression+  --+  = Expression P.Expr+  -- |+  -- Show the help (ie, list of directives)+  --+  | ShowHelp+  -- |+  -- Import a module from a loaded file+  --+  | Import ImportedModule+  -- |+  -- Browse a module+  --+  | BrowseModule P.ModuleName+  -- |+  -- Load a file for use with importing+  --+  | LoadFile FilePath+  -- |+  -- Exit PSCI+  --+  | QuitPSCi+  -- |+  -- Reset the state of the REPL+  --+  | ResetState+  -- |+  -- Add some declarations to the current evaluation context.+  --+  | Decls [P.Declaration]+  -- |+  -- Find the type of an expression+  --+  | TypeOf P.Expr+  -- |+  -- Find the kind of an expression+  --+  | KindOf P.Type+  -- |+  -- Shows information about the current state of the REPL+  --+  | ShowInfo ReplQuery++data ReplQuery+  = QueryLoaded+  | QueryImport+  deriving (Eq, Show)++-- | A list of all ReplQuery values.+replQueries :: [ReplQuery]+replQueries = [QueryLoaded, QueryImport]++replQueryStrings :: [String]+replQueryStrings = map showReplQuery replQueries++showReplQuery :: ReplQuery -> String+showReplQuery QueryLoaded = "loaded"+showReplQuery QueryImport = "import"++parseReplQuery :: String -> Maybe ReplQuery+parseReplQuery "loaded" = Just QueryLoaded+parseReplQuery "import" = Just QueryImport+parseReplQuery _ = Nothing++data Directive+  = Help+  | Quit+  | Reset+  | Browse+  | Load+  | Type+  | Kind+  | Show+  deriving (Eq, Show)
+ psci/main/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import PSCi++main :: IO ()+main = runPSCi
+ psci/tests/Main.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE RecordWildCards #-}++module Main where++import Control.Monad.Trans.State.Strict (runStateT)+import Control.Monad (when)++import System.Exit (exitFailure)+import System.Console.Haskeline++import Test.HUnit++import qualified Language.PureScript as P++import PSCi+import Completion+import Types++main :: IO ()+main = do+  Counts{..} <- runTestTT allTests+  when (errors + failures > 0) exitFailure++allTests :: Test+allTests = completionTests++completionTests :: Test+completionTests =+  TestLabel "completionTests"+    (TestList (map (TestCase . assertCompletedOk) completionTestData))++-- If the cursor is at the right end of the line, with the 1st element of the+-- pair as the text in the line, then pressing tab should offer all the+-- elements of the list (which is the 2nd element) as completions.+completionTestData :: [(String, [String])]+completionTestData =+  -- basic directives+  [ (":h", [":help"])+  , (":re", [":reset"])+  , (":q", [":quit"])+  , (":mo", [":module"])+  , (":b", [":browse"])++  -- :browse should complete modules+  , (":b Prel", [":b Prelude", ":b Prelude.Unsafe"])+  , (":b Prelude.", [":b Prelude.Unsafe"])++  -- :load, :module should complete file paths+  , (":l psci/tests/data/", [":l psci/tests/data/Sample.purs"])+  , (":module psci/tests/data/", [":module psci/tests/data/Sample.purs"])++  -- :quit, :help, :reset should not complete+  , (":help ", [])+  , (":quit ", [])+  , (":reset ", [])++  -- :show should complete to "loaded" and "import"+  , (":show ", [":show import", ":show loaded"])+  , (":show a", [])++  -- :type should complete values and data constructors in scope+  , (":type Prelude.Unsafe.un", [":type Prelude.Unsafe.unsafeIndex"])+  , (":type un", [":type unit"])+  , (":type E", [":type EQ"])++  -- :kind should complete types in scope+  , (":kind C", [":kind Control.Monad.Eff.Pure"])+  , (":kind O", [":kind Ordering"])++  -- Only one argument for directives should be completed+  , (":show import ", [])+  , (":type EQ ", [])+  , (":kind Ordering ", [])++  -- import should complete module names+  , ("import Control.Monad.S", ["import Control.Monad.ST"])+  , ("import qualified Control.Monad.S", ["import qualified Control.Monad.ST"])+  , ("import Control.Monad.", map ("import Control.Monad." ++)+                                  ["Eff", "Eff.Unsafe", "ST"])++  -- a few other import tests+  , ("impor", ["import"])+  , ("import q", ["import qualified"])+  , ("import ", map ("import " ++) allModuleNames ++ ["import qualified"])+  , ("import Prelude.Unsafe ", [])++  -- String and number literals should not be completed+  , ("\"hi", [])+  , ("34", [])++  -- Identifiers and data constructors should be completed+  , ("un", ["unit"])+  , ("Debug.Trace.", map ("Debug.Trace." ++) ["print", "trace"])+  , ("G", ["GT"])+  , ("Prelude.L", ["Prelude.LT"])++  -- if a module is imported qualified, values should complete under the+  -- qualified name, as well as the original name.+  , ("ST.new", ["ST.newSTRef"])+  , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])+  ]+  where+  allModuleNames = [ "Control.Monad.Eff"+                   , "Control.Monad.Eff.Unsafe"+                   , "Control.Monad.ST"+                   , "Data.Function"+                   , "Debug.Trace"+                   , "Prelude"+                   , "Prelude.Unsafe"+                   ]++assertCompletedOk :: (String, [String]) -> Assertion+assertCompletedOk (line, expecteds) = do+  (unusedR, completions) <- runCM (completion' (reverse line, ""))+  let unused = reverse unusedR+  let actuals = map ((unused ++) . replacement) completions+  expecteds @=? actuals++runCM :: CompletionM a -> IO a+runCM act = do+  psciState <- getPSCiState+  fmap fst (runStateT (liftCompletionM act) psciState)++getPSCiState :: IO PSCiState+getPSCiState = do+  modulesOrFirstError <- loadAllModules []+  case modulesOrFirstError of+    Left err ->+      print err >> exitFailure+    Right modules ->+      let imports = controlMonadSTasST : defaultImports+      in  return (PSCiState [] imports modules [] [])++controlMonadSTasST :: ImportedModule+controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))+  where+  s = P.moduleNameFromString
purescript.cabal view
@@ -1,5 +1,5 @@ name: purescript-version: 0.6.9.3+version: 0.6.9.4 cabal-version: >=1.8 build-type: Simple license: MIT@@ -148,10 +148,12 @@      main-is: Main.hs     buildable: True-    hs-source-dirs: psci-    other-modules: Commands+    hs-source-dirs: psci psci/main+    other-modules: Types                    Parser                    Directive+                   Completion+                   PSCi     ghc-options: -Wall -O2  executable psc-docs@@ -182,3 +184,14 @@     main-is: Main.hs     buildable: True     hs-source-dirs: tests++test-suite psci-tests+    build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,+                   mtl -any, optparse-applicative >= 0.10.0, parsec -any,+                   haskeline >= 0.7.0.0, purescript -any, transformers -any,+                   process -any, HUnit -any+    type: exitcode-stdio-1.0+    main-is: Main.hs+    buildable: True+    hs-source-dirs: psci psci/tests+    ghc-options: -Wall
src/Language/PureScript.hs view
@@ -89,20 +89,20 @@ -- --  * Pretty-print the generated Javascript ---compile :: (Functor m, Applicative m, MonadError String m, MonadReader (Options Compile) m)+compile :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadReader (Options Compile) m)         => [Module] -> [String] -> m (String, String, Environment) compile = compile' initEnvironment -compile' :: (Functor m, Applicative m, MonadError String m, MonadReader (Options Compile) m)+compile' :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadReader (Options Compile) m)          => Environment -> [Module] -> [String] -> m (String, String, Environment) compile' env ms prefix = do   noPrelude <- asks optionsNoPrelude   additional <- asks optionsAdditional   mainModuleIdent <- asks (fmap moduleNameFromString . optionsMain)   (sorted, _) <- sortModules $ map importPrim $ if noPrelude then ms else map importPrelude ms-  (desugared, nextVar) <- interpretMultipleErrors True $ runSupplyT 0 $ desugar sorted+  (desugared, nextVar) <- runSupplyT 0 $ desugar sorted   (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent-  regrouped <- interpretMultipleErrors True $ createBindingGroupsModule . collapseBindingGroupsModule $ elaborated+  regrouped <- 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@@ -115,21 +115,21 @@   let pjs = unlines $ map ("// " ++) prefix ++ [prettyPrintJS js']   return (pjs, exts, env') -generateMain :: (MonadError String m, MonadReader (Options Compile) m) => Environment -> [JS] -> m [JS]+generateMain :: (MonadError MultipleErrors m, MonadReader (Options Compile) m) => Environment -> [JS] -> m [JS] generateMain env js = do   main <- asks optionsMain   additional <- asks optionsAdditional   case moduleNameFromString <$> main of     Just mmi -> do       when ((mmi, Ident C.main) `M.notMember` names env) $-        throwError $ show mmi ++ "." ++ C.main ++ " is undefined"+        throwError . errorMessage $ NameIsUndefined (Ident C.main)       return $ js ++ [JSApp (JSAccessor C.main (JSAccessor (moduleNameToJs mmi) (JSVar (browserNamespace additional)))) []]     _ -> return js  -- | -- A type class which collects the IO actions we need to be able to run in "make" mode ---class (MonadReader (P.Options P.Make) m, MonadError String m) => MonadMake m where+class (MonadReader (P.Options P.Make) m, MonadError MultipleErrors m) => MonadMake m where   -- |   -- Get a file timestamp   --@@ -196,7 +196,7 @@    marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted -  (desugared, nextVar) <- interpretMultipleErrors True $ runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)+  (desugared, nextVar) <- runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)    evalSupplyT nextVar $ go initEnvironment desugared @@ -216,7 +216,7 @@      (Module _ _ elaborated _, env') <- lift . runCheck' env $ typeCheckModule Nothing m -    regrouped <- interpretMultipleErrors True . createBindingGroups moduleName' . collapseBindingGroups $ elaborated+    regrouped <- createBindingGroups moduleName' . collapseBindingGroups $ elaborated      let mod' = Module coms moduleName' regrouped exps     let corefn = CoreFn.moduleToCoreFn env' mod'@@ -240,10 +240,10 @@   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)]+    externsModules <- fmap (map snd) . either (throwError . errorMessage . ErrorParsingExterns) return $ P.parseModulesFromFiles id [(externsFile, externs)]     case externsModules of       [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'-      _ -> throwError $ "Externs file " ++ externsFile ++ " was invalid"+      _ -> throwError . errorMessage . InvalidExternsFile $ externsFile  reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName] reverseDependencies g = combine [ (dep, mn) | (mn, deps) <- g, dep <- deps ]
src/Language/PureScript/AST/Declarations.hs view
@@ -78,12 +78,12 @@ -- | -- Return the exported data constructors for a given type. ---exportedDctors :: Module -> ProperName -> [ProperName]+exportedDctors :: Module -> ProperName -> [(ProperName, [Type])] exportedDctors (Module _ _ decls exps) ident =-  filter (isDctorExported ident exps) dctors+  filter (isDctorExported ident exps . fst) dctors   where   dctors = concatMap getDctors (flattenDecls decls)-  getDctors (DataDeclaration _ _ _ ctors) = map fst ctors+  getDctors (DataDeclaration _ _ _ ctors) = ctors   getDctors (PositionedDeclaration _ _ d) = getDctors d   getDctors _ = [] 
src/Language/PureScript/AST/SourcePos.hs view
@@ -30,10 +30,12 @@     -- Column number     --   , sourcePosColumn :: Int-  } deriving (Eq, D.Data, D.Typeable)+  } deriving (Eq, Show, D.Data, D.Typeable) -instance Show SourcePos where-  show sp = "line " ++ show (sourcePosLine sp) ++ ", column " ++ show (sourcePosColumn sp)+displaySourcePos :: SourcePos -> String+displaySourcePos sp =+  "line " ++ show (sourcePosLine sp) +++    ", column " ++ show (sourcePosColumn sp)  data SourceSpan = SourceSpan   { -- |@@ -47,7 +49,10 @@     -- End of the span     --   , spanEnd :: SourcePos-  } deriving (Eq, D.Data, D.Typeable)+  } deriving (Eq, Show, D.Data, D.Typeable) -instance Show SourceSpan where-  show sp = spanName sp ++ " " ++ show (spanStart sp) ++ " - " ++ show (spanEnd sp)+displaySourceSpan :: SourceSpan -> String+displaySourceSpan sp =+  spanName sp ++ " " +++    displaySourcePos (spanStart sp) ++ " - " +++    displaySourcePos (spanEnd sp)
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs view
@@ -84,10 +84,28 @@ inlineValues = everywhereOnJS convert   where   convert :: JS -> JS-  convert (JSApp fn [dict]) | isPreludeDict C.semiringNumber dict && isPreludeFn C.zero fn = JSNumericLiteral (Left 0)-  convert (JSApp fn [dict]) | isPreludeDict C.semiringNumber dict && isPreludeFn C.one fn = JSNumericLiteral (Left 1)-  convert (JSApp (JSApp fn [x]) [y]) | isPreludeFn (C.%) fn = JSBinary Modulus x y+  convert (JSApp fn [dict]) | isDict semiringNumber dict && isFn fnZero fn = JSNumericLiteral (Left 0)+                            | isDict semiringNumber dict && isFn fnOne fn = JSNumericLiteral (Left 1)+                            | isDict semiringInt dict && isFn fnZero fn = JSNumericLiteral (Left 0)+                            | isDict semiringInt dict && isFn fnOne fn = JSNumericLiteral (Left 1)+                            | isDict boundedBoolean dict && isFn fnBottom fn = JSBooleanLiteral False+                            | isDict boundedBoolean dict && isFn fnTop fn = JSBooleanLiteral True+  convert (JSApp fn [value]) | isFn fromNumber fn = JSBinary BitwiseOr value (JSNumericLiteral (Left 0))+  convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y])+    | isDict semiringInt dict && isFn fnAdd fn = JSBinary BitwiseOr (JSBinary Add x y) (JSNumericLiteral (Left 0))+    | isDict semiringInt dict && isFn fnMultiply fn = JSBinary BitwiseOr (JSBinary Multiply x y) (JSNumericLiteral (Left 0))+    | isDict moduloSemiringInt dict && isFn fnDivide fn = JSBinary BitwiseOr (JSBinary Divide x y) (JSNumericLiteral (Left 0))+    | isDict ringInt dict && isFn fnSubtract fn = JSBinary BitwiseOr (JSBinary Subtract x y) (JSNumericLiteral (Left 0))   convert other = other+  fnZero = (C.prelude, C.zero)+  fnOne = (C.prelude, C.one)+  fnBottom = (C.prelude, C.bottom)+  fnTop = (C.prelude, C.top)+  fromNumber = (C.dataInt, C.fromNumber)+  fnAdd = (C.prelude, (C.+))+  fnDivide = (C.prelude, (C./))+  fnMultiply = (C.prelude, (C.*))+  fnSubtract = (C.prelude, (C.-))  inlineOperator :: (String, String) -> (JS -> JS -> JS) -> JS -> JS inlineOperator (m, op) f = everywhereOnJS convert@@ -101,59 +119,84 @@  inlineCommonOperators :: JS -> JS inlineCommonOperators = applyAll $-  [ binary C.semiringNumber (C.+) Add-  , binary C.semiringNumber (C.*) Multiply-  , binary C.ringNumber (C.-) Subtract-  , unary  C.ringNumber C.negate Negate-  , binary C.moduloSemiringNumber (C./) Divide+  [ binary semiringNumber (C.+) Add+  , binary semiringNumber (C.*) Multiply -  , binary C.ordNumber (C.<) LessThan-  , binary C.ordNumber (C.>) GreaterThan-  , binary C.ordNumber (C.<=) LessThanOrEqualTo-  , binary C.ordNumber (C.>=) GreaterThanOrEqualTo+  , binary ringNumber (C.-) Subtract+  , unary  ringNumber C.negate Negate+  , binary ringInt (C.-) Subtract+  , unary  ringInt C.negate Negate -  , binary C.eqNumber (C.==) EqualTo-  , binary C.eqNumber (C./=) NotEqualTo-  , binary C.eqString (C.==) EqualTo-  , binary C.eqString (C./=) NotEqualTo-  , binary C.eqBoolean (C.==) EqualTo-  , binary C.eqBoolean (C./=) NotEqualTo+  , binary moduloSemiringNumber (C./) Divide+  , binary moduloSemiringInt C.mod Modulus -  , binary C.semigroupString (C.<>) Add-  , binary C.semigroupString (C.++) Add+  , binary eqNumber (C.==) EqualTo+  , binary eqNumber (C./=) NotEqualTo+  , binary eqInt (C.==) EqualTo+  , binary eqInt (C./=) NotEqualTo+  , binary eqString (C.==) EqualTo+  , binary eqString (C./=) NotEqualTo+  , binary eqBoolean (C.==) EqualTo+  , binary eqBoolean (C./=) NotEqualTo -  , binaryFunction C.bitsNumber C.shl ShiftLeft-  , binaryFunction C.bitsNumber C.shr ShiftRight-  , binaryFunction C.bitsNumber C.zshr ZeroFillShiftRight-  , binary         C.bitsNumber (C..&.) BitwiseAnd-  , binary         C.bitsNumber (C..|.) BitwiseOr-  , binary         C.bitsNumber (C..^.) BitwiseXor-  , unary          C.bitsNumber C.complement BitwiseNot+  , binary ordNumber (C.<) LessThan+  , binary ordNumber (C.>) GreaterThan+  , binary ordNumber (C.<=) LessThanOrEqualTo+  , binary ordNumber (C.>=) GreaterThanOrEqualTo+  , binary ordInt (C.<) LessThan+  , binary ordInt (C.>) GreaterThan+  , binary ordInt (C.<=) LessThanOrEqualTo+  , binary ordInt (C.>=) GreaterThanOrEqualTo -  , binary C.boolLikeBoolean (C.&&) And-  , binary C.boolLikeBoolean (C.||) Or-  , unary  C.boolLikeBoolean C.not Not+  , binary semigroupString (C.<>) Add+  , binary semigroupString (C.++) Add++  , binary latticeBoolean (C.&&) And+  , binary latticeBoolean (C.||) Or+  , binaryFunction latticeBoolean C.inf And+  , binaryFunction latticeBoolean C.sup Or+  , unary complementedLatticeBoolean C.not Not++  , binary' C.dataIntBits (C..|.) BitwiseOr+  , binary' C.dataIntBits (C..&.) BitwiseAnd+  , binary' C.dataIntBits (C..^.) BitwiseXor+  , binary' C.dataIntBits C.shl ShiftLeft+  , binary' C.dataIntBits C.shr ShiftRight+  , binary' C.dataIntBits C.zshr ZeroFillShiftRight+  , unary'  C.dataIntBits C.complement BitwiseNot   ] ++   [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]   where-  binary :: String -> String -> BinaryOperator -> JS -> JS-  binary dictName opString op = everywhereOnJS convert+  binary :: (String, String) -> String -> BinaryOperator -> JS -> JS+  binary dict opString op = everywhereOnJS convert     where     convert :: JS -> JS-    convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isPreludeDict dictName dict && isPreludeFn opString fn = JSBinary op x y+    convert (JSApp (JSApp (JSApp fn [dict']) [x]) [y]) | isDict dict dict' && isPreludeFn opString fn = JSBinary op x y     convert other = other-  binaryFunction :: String -> String -> BinaryOperator -> JS -> JS-  binaryFunction dictName fnName op = everywhereOnJS convert+  binary' :: String -> String -> BinaryOperator -> JS -> JS+  binary' moduleName opString op = everywhereOnJS convert     where     convert :: JS -> JS-    convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isPreludeFn fnName fn && isPreludeDict dictName dict = JSBinary op x y+    convert (JSApp (JSApp fn [x]) [y]) | isFn (moduleName, opString) fn = JSBinary op x y     convert other = other-  unary :: String -> String -> UnaryOperator -> JS -> JS-  unary dictName fnName op = everywhereOnJS convert+  binaryFunction :: (String, String) -> String -> BinaryOperator -> JS -> JS+  binaryFunction dict fnName op = everywhereOnJS convert     where     convert :: JS -> JS-    convert (JSApp (JSApp fn [dict]) [x]) | isPreludeFn fnName fn && isPreludeDict dictName dict = JSUnary op x+    convert (JSApp (JSApp (JSApp fn [dict']) [x]) [y]) | isPreludeFn fnName fn && isDict dict dict' = JSBinary op x y     convert other = other+  unary :: (String, String) -> String -> UnaryOperator -> JS -> JS+  unary dict fnName op = everywhereOnJS convert+    where+    convert :: JS -> JS+    convert (JSApp (JSApp fn [dict']) [x]) | isPreludeFn fnName fn && isDict dict dict' = JSUnary op x+    convert other = other+  unary' :: String -> String -> UnaryOperator -> JS -> JS+  unary' moduleName fnName op = everywhereOnJS convert+    where+    convert :: JS -> JS+    convert (JSApp fn [x]) | isFn (moduleName, fnName) fn = JSUnary op x+    convert other = other   mkFn :: Int -> JS -> JS   mkFn 0 = everywhereOnJS convert     where@@ -190,12 +233,62 @@     go m acc (JSApp lhs [arg]) = go (m - 1) (arg : acc) lhs     go _ _   _ = Nothing -isPreludeDict :: String -> JS -> Bool-isPreludeDict dictName (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && prop == dictName-isPreludeDict _ _ = False+isDict :: (String, String) -> JS -> Bool+isDict (moduleName, dictName) (JSAccessor x (JSVar y)) = x == dictName && y == moduleName+isDict _ _ = False +isFn :: (String, String) -> JS -> Bool+isFn (moduleName, fnName) (JSAccessor x (JSVar y)) = x == fnName && y == moduleName+isFn (moduleName, fnName) (JSIndexer (JSStringLiteral x) (JSVar y)) = x == fnName && y == moduleName+isFn _ _ = False+ isPreludeFn :: String -> JS -> Bool-isPreludeFn fnName (JSAccessor fnName' (JSVar prelude)) = prelude == C.prelude && fnName' == fnName-isPreludeFn fnName (JSIndexer (JSStringLiteral fnName') (JSVar prelude)) = prelude == C.prelude && fnName' == fnName-isPreludeFn fnName (JSAccessor longForm (JSAccessor prelude (JSVar _))) = prelude == C.prelude && longForm == identToJs (Op fnName)-isPreludeFn _ _ = False+isPreludeFn fnName = isFn (C.prelude, fnName)++semiringNumber :: (String, String)+semiringNumber = (C.prelude, C.semiringNumber)++semiringInt :: (String, String)+semiringInt = (C.dataInt, C.semiringInt)++ringNumber :: (String, String)+ringNumber = (C.prelude, C.ringNumber)++ringInt :: (String, String)+ringInt = (C.dataInt, C.ringInt)++moduloSemiringNumber :: (String, String)+moduloSemiringNumber = (C.prelude, C.moduloSemiringNumber)++moduloSemiringInt :: (String, String)+moduloSemiringInt = (C.dataInt, C.moduloSemiringInt)++eqNumber :: (String, String)+eqNumber = (C.prelude, C.eqNumber)++eqInt :: (String, String)+eqInt = (C.dataInt, C.eqInt)++eqString :: (String, String)+eqString = (C.prelude, C.eqNumber)++eqBoolean :: (String, String)+eqBoolean = (C.prelude, C.eqNumber)++ordNumber :: (String, String)+ordNumber = (C.prelude, C.ordNumber)++ordInt :: (String, String)+ordInt = (C.dataInt, C.ordInt)++semigroupString :: (String, String)+semigroupString = (C.prelude, C.semigroupString)++boundedBoolean :: (String, String)+boundedBoolean = (C.prelude, C.boundedBoolean)++latticeBoolean :: (String, String)+latticeBoolean = (C.prelude, C.latticeBoolean)++complementedLatticeBoolean :: (String, String)+complementedLatticeBoolean = (C.prelude, C.complementedLatticeBoolean)
src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs view
@@ -15,6 +15,8 @@  module Language.PureScript.CodeGen.JS.Optimizer.TCO (tco) where +import Data.Monoid+ import Language.PureScript.Options import Language.PureScript.CodeGen.JS.AST @@ -30,10 +32,13 @@   where   tcoLabel :: String   tcoLabel = "tco"+   tcoVar :: String -> String   tcoVar arg = "__tco_" ++ arg+   copyVar :: String -> String   copyVar arg = "__copy_" ++ arg+   convert :: JS -> JS   convert js@(JSVariableIntroduction name (Just fn@JSFunction {})) =     let@@ -46,6 +51,7 @@               JSVariableIntroduction name (Just (replace (toLoop name allArgs body')))         | otherwise -> js   convert js = js+   collectAllFunctionArgs :: [[String]] -> (JS -> JS) -> JS -> ([[String]], JS, JS -> JS)   collectAllFunctionArgs allArgs f (JSFunction ident args (JSBlock (body@(JSReturn _):_))) =     collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction ident (map copyVar args) (JSBlock [b]))) body@@ -56,25 +62,35 @@   collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args body@(JSBlock _))) =     (args : allArgs, body, f . JSReturn . JSFunction ident (map copyVar args))   collectAllFunctionArgs allArgs f body = (allArgs, body, f)+   isTailCall :: String -> JS -> Bool   isTailCall ident js =     let       numSelfCalls = everythingOnJS (+) countSelfCalls js       numSelfCallsInTailPosition = everythingOnJS (+) countSelfCallsInTailPosition js       numSelfCallsUnderFunctions = everythingOnJS (+) countSelfCallsUnderFunctions js+      numSelfCallWithFnArgs = everythingOnJS (+) countSelfCallsWithFnArgs js     in       numSelfCalls > 0       && numSelfCalls == numSelfCallsInTailPosition       && numSelfCallsUnderFunctions == 0+      && numSelfCallWithFnArgs == 0     where     countSelfCalls :: JS -> Int     countSelfCalls (JSApp (JSVar ident') _) | ident == ident' = 1     countSelfCalls _ = 0+         countSelfCallsInTailPosition :: JS -> Int     countSelfCallsInTailPosition (JSReturn ret) | isSelfCall ident ret = 1     countSelfCallsInTailPosition _ = 0+    +    countSelfCallsUnderFunctions :: JS -> Int     countSelfCallsUnderFunctions (JSFunction _ _ js') = everythingOnJS (+) countSelfCalls js'     countSelfCallsUnderFunctions _ = 0+    +    countSelfCallsWithFnArgs :: JS -> Int+    countSelfCallsWithFnArgs ret = if isSelfCallWithFnArgs ident ret [] then 1 else 0+   toLoop :: String -> [String] -> JS -> JS   toLoop ident allArgs js = JSBlock $         map (\arg -> JSVariableIntroduction arg (Just (JSVar (copyVar arg)))) allArgs ++@@ -94,10 +110,19 @@     collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]     collectSelfCallArgs allArgumentValues (JSApp fn args') = collectSelfCallArgs (args' : allArgumentValues) fn     collectSelfCallArgs allArgumentValues _ = allArgumentValues+   isSelfCall :: String -> JS -> Bool-  isSelfCall ident (JSApp (JSVar ident') args) | ident == ident' && not (any isFunction args) = True-  isSelfCall ident (JSApp fn args) | not (any isFunction args) = isSelfCall ident fn+  isSelfCall ident (JSApp (JSVar ident') _) = ident == ident'+  isSelfCall ident (JSApp fn _) = isSelfCall ident fn   isSelfCall _ _ = False-  isFunction :: JS -> Bool-  isFunction (JSFunction _ _ _) = True-  isFunction _ = False++  isSelfCallWithFnArgs :: String -> JS -> [JS] -> Bool+  isSelfCallWithFnArgs ident (JSVar ident') args | ident == ident' && any hasFunction args = True+  isSelfCallWithFnArgs ident (JSApp fn args) acc = isSelfCallWithFnArgs ident fn (args ++ acc)+  isSelfCallWithFnArgs _ _ _ = False+    +  hasFunction :: JS -> Bool +  hasFunction = getAny . everythingOnJS mappend (Any . isFunction)+    where+    isFunction (JSFunction _ _ _) = True+    isFunction _ = False
src/Language/PureScript/Constants.hs view
@@ -15,7 +15,7 @@  module Language.PureScript.Constants where --- Prelude Operators+-- Operators  ($) :: String ($) = "$"@@ -65,15 +65,6 @@ (/=) :: String (/=) = "/=" -(.&.) :: String-(.&.) = ".&."--(.|.) :: String-(.|.) = ".|."--(.^.) :: String-(.^.) = ".^."- (&&) :: String (&&) = "&&" @@ -83,11 +74,32 @@ unsafeIndex :: String unsafeIndex = "unsafeIndex" --- Prelude Operator Functions+(.|.) :: String+(.|.) = ".|." +(.&.) :: String+(.&.) = ".&."++(.^.) :: String+(.^.) = ".^."++-- Functions+ negate :: String negate = "negate" +not :: String+not = "not"++sup :: String+sup = "sup"++inf :: String+inf = "inf"++mod :: String+mod = "mod"+ shl :: String shl = "shl" @@ -100,8 +112,8 @@ complement :: String complement = "complement" -not :: String-not = "not"+fromNumber :: String+fromNumber = "fromNumber"  -- Prelude Values @@ -111,6 +123,12 @@ one :: String one = "one" +bottom :: String+bottom = "bottom"++top :: String+top = "top"+ return :: String return = "return" @@ -172,33 +190,48 @@ semiringNumber :: String semiringNumber = "semiringNumber" +semiringInt :: String+semiringInt = "semiringInt"+ ringNumber :: String ringNumber = "ringNumber" +ringInt :: String+ringInt = "ringInt"+ moduloSemiringNumber :: String moduloSemiringNumber = "moduloSemiringNumber" -numNumber :: String-numNumber = "numNumber"+moduloSemiringInt :: String+moduloSemiringInt = "moduloSemiringInt"  ordNumber :: String ordNumber = "ordNumber" +ordInt :: String+ordInt = "ordInt"+ eqNumber :: String eqNumber = "eqNumber" +eqInt :: String+eqInt = "eqInt"+ eqString :: String eqString = "eqString"  eqBoolean :: String eqBoolean = "eqBoolean" -bitsNumber :: String-bitsNumber = "bitsNumber"+boundedBoolean :: String+boundedBoolean = "boundedBoolean" -boolLikeBoolean :: String-boolLikeBoolean = "boolLikeBoolean"+latticeBoolean :: String+latticeBoolean = "latticeBoolean" +complementedLatticeBoolean :: String+complementedLatticeBoolean = "complementedLatticeBoolean"+ semigroupString :: String semigroupString = "semigroupString" @@ -237,3 +270,9 @@  dataFunction :: String dataFunction = "Data_Function"++dataInt :: String+dataInt = "Data_Int"++dataIntBits :: String+dataIntBits = "Data_Int_Bits"
src/Language/PureScript/Errors.hs view
@@ -36,11 +36,19 @@  import qualified Text.PrettyPrint.Boxes as Box +import qualified Text.Parsec as P+ -- | -- A type of error messages -- data ErrorMessage -  = InfiniteType Type+  = ErrorParsingExterns P.ParseError+  | ErrorParsingPrelude P.ParseError+  | InvalidExternsFile FilePath+  | CannotGetFileInfo FilePath+  | CannotReadFile FilePath+  | CannotWriteFile FilePath+  | InfiniteType Type   | InfiniteKind Kind   | CannotReorderOperators   | MultipleFixities Ident@@ -70,6 +78,7 @@   | InvalidDoLet   | CycleInDeclaration Ident   | CycleInTypeSynonym (Maybe ProperName)+  | CycleInModules [ModuleName]   | NameIsUndefined Ident   | NameNotInScope Ident   | UndefinedTypeVariable ProperName@@ -126,6 +135,12 @@ -- Get the error code for a particular error type -- errorCode :: ErrorMessage -> String+errorCode (ErrorParsingExterns _)       = "ErrorParsingExterns"+errorCode (ErrorParsingPrelude _)       = "ErrorParsingPrelude"+errorCode (InvalidExternsFile _)        = "InvalidExternsFile"+errorCode (CannotGetFileInfo _)         = "CannotGetFileInfo"+errorCode (CannotReadFile _)            = "CannotReadFile"+errorCode (CannotWriteFile _)           = "CannotWriteFile" errorCode (InfiniteType _)              = "InfiniteType" errorCode (InfiniteKind _)              = "InfiniteKind" errorCode CannotReorderOperators        = "CannotReorderOperators"@@ -156,6 +171,7 @@ errorCode InvalidDoLet                  = "InvalidDoLet" errorCode (CycleInDeclaration _)        = "CycleInDeclaration" errorCode (CycleInTypeSynonym _)        = "CycleInTypeSynonym"+errorCode (CycleInModules _)            = "CycleInModules" errorCode (NameIsUndefined _)           = "NameIsUndefined" errorCode (NameNotInScope _)            = "NameNotInScope" errorCode (UndefinedTypeVariable _)     = "UndefinedTypeVariable"@@ -177,13 +193,13 @@ 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 (ErrorUnifyingTypes _ _ e)    = errorCode e errorCode (ErrorInExpression _ e)       = errorCode e errorCode (ErrorInModule _ e)           = errorCode e errorCode (ErrorInInstance _ _ e)       = errorCode e@@ -245,6 +261,24 @@     wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e            go :: ErrorMessage -> Box.Box+    go (CannotGetFileInfo path)        = paras [ line "Unable to read file info: "+                                               , indent . line $ path+                                               ]+    go (CannotReadFile path)           = paras [ line "Unable to read file: "+                                               , indent . line $ path+                                               ]+    go (CannotWriteFile path)          = paras [ line "Unable to write file: "+                                               , indent . line $ path+                                               ]+    go (ErrorParsingExterns err)       = paras [ line "Error parsing externs files: "+                                               , indent . line . show $ err+                                               ]+    go (ErrorParsingPrelude err)       = paras [ line "Error parsing prelude: "+                                               , indent . line . show $ err+                                               ]+    go (InvalidExternsFile path)       = paras [ line "Externs file is invalid: "+                                               , indent . line $ path+                                               ]     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"@@ -278,6 +312,7 @@     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 (CycleInModules mns)            = line $ "Cycle in module dependencies: " ++ intercalate ", " (map show mns)     go (NotYetDefined names err)       = paras [ line $ "The following are not yet defined here: " ++ intercalate ", " (map show names) ++ ":"                                                , indent $ go err                                                ]@@ -404,7 +439,7 @@     go (ErrorInForeignImport nm err)   = paras [ line $ "Error in foreign import " ++ show nm ++ ":"                                                , go err                                                ]-    go (PositionedError pos err)       = paras [ line $ "Error at " ++ show pos ++ ":"+    go (PositionedError srcSpan err)   = paras [ line $ "Error at " ++ displaySourceSpan srcSpan ++ ":"                                                , indent $ go err                                                ] @@ -490,8 +525,8 @@ -- | -- 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+interpretMultipleErrors :: (MonadError MultipleErrors m) => Either MultipleErrors a -> m a+interpretMultipleErrors = either throwError return  -- | -- Rethrow an error with a more detailed error message in the case of failure
src/Language/PureScript/ModuleDependencies.hs view
@@ -28,6 +28,7 @@ import Language.PureScript.AST import Language.PureScript.Names import Language.PureScript.Types+import Language.PureScript.Errors  -- | -- A list of modules with their dependencies@@ -39,7 +40,7 @@ -- -- Reports an error if the module graph contains a cycle. ---sortModules :: (MonadError String m) => [Module] -> m ([Module], ModuleGraph)+sortModules :: (MonadError MultipleErrors m) => [Module] -> m ([Module], ModuleGraph) sortModules ms = do   let verts = map (\m@(Module _ _ ds _) -> (m, getModuleName m, nub (concatMap usedModules ds))) ms   ms' <- mapM toModule $ stronglyConnComp verts@@ -70,7 +71,7 @@ -- | -- Convert a strongly connected component of the module graph to a module ---toModule :: (MonadError String m) => SCC Module -> m Module+toModule :: (MonadError MultipleErrors m) => SCC Module -> m Module toModule (AcyclicSCC m) = return m toModule (CyclicSCC [m]) = return m-toModule (CyclicSCC ms) = throwError $ "Cycle in module dependencies: " ++ show (map getModuleName ms)+toModule (CyclicSCC ms) = throwError . errorMessage $ CycleInModules (map getModuleName ms)
src/Language/PureScript/Parser/Types.hs view
@@ -126,9 +126,7 @@ parseNameAndType p = (,) <$> (indented *> (lname <|> stringLiteral) <* indented <* doubleColon) <*> p  parseRowEnding :: TokenParser Type-parseRowEnding = P.option REmpty $ indented *> pipe *> indented *> P.choice  (map P.try-            [ parseTypeWildcard-            , TypeVar <$> identifier ])+parseRowEnding = P.option REmpty $ indented *> pipe *> indented *> parseType  parseRow :: TokenParser Type parseRow = (curry rowFromList <$> commaSep (parseNameAndType parsePolyType) <*> parseRowEnding) P.<?> "row"
src/Language/PureScript/Sugar/BindingGroups.hs view
@@ -157,7 +157,6 @@ -- 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') =   -- Once we have a mutually-recursive group of declarations, we need to sort   -- them further by their immediate dependencies (those outside function
src/Language/PureScript/Sugar/CaseDeclarations.hs view
@@ -21,10 +21,11 @@     desugarCasesModule ) where +import Data.Maybe (catMaybes) import Data.List (nub, groupBy)  import Control.Applicative-import Control.Monad ((<=<), forM, join, unless, replicateM)+import Control.Monad ((<=<), forM, replicateM, join, unless) import Control.Monad.Except (throwError) import Control.Monad.Error.Class (MonadError) import Control.Monad.Supply.Class@@ -120,31 +121,53 @@ makeCaseDeclaration :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> m Declaration makeCaseDeclaration ident alternatives = do   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+      argNames = map join $ foldl1 resolveNames namedArgs+  args <- if allUnique (catMaybes argNames) +            then mapM argName argNames +            else replicateM (length argNames) (Ident <$> freshName)+  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+  -- We will construct a table of potential names.+  -- VarBinders will become Just (Just _) which is a potential name.+  -- NullBinder will become Just Nothing, which indicates that we may +  -- have to generate a name.+  -- Everything else becomes Nothing, which indicates that we definitely+  --have to generate a name.+  findName :: Binder -> Maybe (Maybe Ident)+  findName NullBinder = Just Nothing+  findName (VarBinder name) = Just (Just name)   findName (PositionedBinder _ _ binder) = findName binder   findName _ = Nothing +  -- We still have to make sure the generated names are unique, or else+  -- we will end up constructing an invalid function.+  allUnique :: (Eq a) => [a] -> Bool+  allUnique xs = length xs == length (nub xs)+   argName :: (MonadSupply m) => Maybe Ident -> m Ident   argName (Just name) = return name-  argName Nothing = do+  argName _ = do     name <- freshName     return (Ident name) -  resolveNames :: [Maybe Ident] -> [Maybe Ident] -> [Maybe Ident]+  -- Combine two lists of potential names from two case alternatives+  -- by zipping correspoding columns.+  resolveNames :: [Maybe (Maybe Ident)] -> +                  [Maybe (Maybe Ident)] -> +                  [Maybe (Maybe Ident)]   resolveNames = zipWith resolveName -  resolveName :: Maybe Ident -> Maybe Ident -> Maybe Ident-  resolveName (Just a) (Just b)-    | a == b = Just a+  -- Resolve a pair of names. VarBinder beats NullBinder, and everything+  -- else results in Nothing.+  resolveName :: Maybe (Maybe Ident) -> +                 Maybe (Maybe Ident) -> +                 Maybe (Maybe Ident)+  resolveName (Just (Just a)) (Just (Just b))+    | a == b = Just (Just a)     | otherwise = Nothing-  resolveName Nothing Nothing = Nothing-  resolveName (Just a) Nothing = Just a-  resolveName Nothing (Just b) = Just b+  resolveName (Just Nothing) a = a+  resolveName a (Just Nothing) = a+  resolveName _ _ = Nothing
src/Language/PureScript/Sugar/DoNotation.hs view
@@ -44,11 +44,8 @@   let (f, _, _) = everywhereOnValuesM return replace return   in f d   where-  prelude :: ModuleName-  prelude = ModuleName [ProperName C.prelude]-   bind :: Expr-  bind = Var (Qualified (Just prelude) (Op (C.>>=)))+  bind = Var (Qualified Nothing (Op (C.>>=)))    replace :: Expr -> m Expr   replace (Do els) = go els
src/Language/PureScript/TypeChecker/Entailment.hs view
@@ -116,7 +116,7 @@       checkOverlaps :: [DictionaryValue] -> Check Expr       checkOverlaps dicts =         case [ (d1, d2) | d1 <- dicts, d2 <- dicts, d1 `overlapping` d2 ] of-          ds@(_ : _) -> throwError . errorMessage $ OverlappingInstances className tys (map fst ds)+          ds@(_ : _) -> throwError . errorMessage $ OverlappingInstances className tys $ nub (map fst ds)           _ -> case chooseSimplestDictionaries dicts of                  [] -> throwError . errorMessage $ NoInstanceFound className tys                  d : _ -> return $ dictionaryValueToValue d
src/Language/PureScript/TypeChecker/Monad.hs view
@@ -23,7 +23,6 @@  import Control.Applicative import Control.Monad.Except-import Control.Monad.Reader.Class import Control.Monad.State import Control.Monad.Unify @@ -31,7 +30,6 @@ import Language.PureScript.Errors import Language.PureScript.Kinds import Language.PureScript.Names-import Language.PureScript.Options import Language.PureScript.TypeClassDictionaries import Language.PureScript.Types @@ -98,12 +96,19 @@ -- | -- Update the visibility of all names to Defined ---makeBindingGroupVisible :: (Functor m, MonadState CheckState m) => m a -> m a-makeBindingGroupVisible action = do-  orig <- get-  modify $ \st -> st { checkEnv = (checkEnv st) { names = M.map (\(ty, nk, _) -> (ty, nk, Defined)) (names . checkEnv $ st) } }+makeBindingGroupVisible :: (Functor m, MonadState CheckState m) => m () +makeBindingGroupVisible = modifyEnv $ \e -> e { names = M.map (\(ty, nk, _) -> (ty, nk, Defined)) (names e) }++-- | Update the visibility of all names to Defined in the scope of the provided action+withBindingGroupVisible :: (Functor m, MonadState CheckState m) => m a -> m a+withBindingGroupVisible action = preservingNames $ makeBindingGroupVisible >> action++-- | Perform an action while preserving the names from the @Environment@.+preservingNames :: (Functor m, MonadState CheckState m) => m a -> m a+preservingNames action = do+  orig <- gets (names . checkEnv)   a <- action-  modify $ \st -> st { checkEnv = (checkEnv st) { names = names . checkEnv $ orig } }+  modifyEnv $ \e -> e { names = orig }   return a  -- |@@ -195,18 +200,16 @@ -- | -- Run a computation in the Check monad, starting with an empty @Environment@ ---runCheck :: (MonadReader (Options mode) m, MonadError String m) => Check a -> m (a, Environment)+runCheck :: (MonadError MultipleErrors m) => Check a -> m (a, Environment) runCheck = runCheck' initEnvironment  -- | -- Run a computation in the Check monad, failing with an error, or succeeding with a return value and the final @Environment@. ---runCheck' :: (MonadReader (Options mode) m, MonadError String m) => Environment -> Check a -> m (a, Environment)-runCheck' env c = do-  verbose <- asks optionsVerboseErrors-  interpretMultipleErrors verbose $ do-    (a, s) <- flip runStateT (CheckState env 0 0 Nothing) $ unCheck c-    return (a, checkEnv s)+runCheck' :: (MonadError MultipleErrors m) => Environment -> Check a -> m (a, Environment)+runCheck' env c = interpretMultipleErrors $ 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/Types.hs view
@@ -247,7 +247,7 @@ infer' (Abs (Left arg) ret) = do   ty <- fresh   Just moduleName <- checkCurrentModule <$> get-  makeBindingGroupVisible $ bindLocalVariables moduleName [(arg, ty, Defined)] $ do+  withBindingGroupVisible $ bindLocalVariables moduleName [(arg, ty, Defined)] $ do     body@(TypedValue _ _ bodyTy) <- infer' ret     return $ TypedValue True (Abs (Left arg) body) $ function ty bodyTy infer' (Abs (Right _) _) = error "Binder was not desugared"@@ -298,7 +298,7 @@ infer' _ = error "Invalid argument to infer"  inferLetBinding :: [Declaration] -> [Declaration] -> Expr -> (Expr -> UnifyT Type Check Expr) -> UnifyT Type Check ([Declaration], Expr)-inferLetBinding seen [] ret j = (,) seen <$> makeBindingGroupVisible (j ret)+inferLetBinding seen [] ret j = (,) seen <$> withBindingGroupVisible (j ret) inferLetBinding seen (ValueDeclaration ident nameKind [] (Right (tv@(TypedValue checkType val ty))) : rest) ret j = do   Just moduleName <- checkCurrentModule <$> get   (kind, args) <- liftCheck $ kindOfWithScopedVars ty@@ -320,7 +320,9 @@   ds1' <- parU typed $ \e -> checkTypedBindingGroupElement moduleName e dict   ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict untypedDict   let ds' = [(ident, LocalVariable, val') | (ident, (val', _)) <- ds1' ++ ds2']-  makeBindingGroupVisible $ bindNames dict $ inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j+  bindNames dict $ do+    makeBindingGroupVisible+    inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j inferLetBinding seen (PositionedDeclaration pos com d : ds) ret j = rethrowWithPosition pos $ do   (d' : ds', val') <- inferLetBinding seen (d : ds) ret j   return (PositionedDeclaration pos com d' : ds', val')@@ -442,7 +444,7 @@   dictNames <- forM constraints $ \(Qualified _ (ProperName className), _) -> do     n <- liftCheck freshDictionaryName     return $ Ident $ "__dict_" ++ className ++ "_" ++ show n-  val' <- makeBindingGroupVisible $ withTypeClassDictionaries (zipWith (\name (className, instanceTy) ->+  val' <- withBindingGroupVisible $ withTypeClassDictionaries (zipWith (\name (className, instanceTy) ->     TypeClassDictionaryInScope name className instanceTy Nothing TCDRegular False) (map (Qualified Nothing) dictNames)       constraints) $ check val ty   return $ TypedValue True (foldr (Abs . Left) val' dictNames) t@@ -468,7 +470,7 @@ check' (Abs (Left arg) ret) ty@(TypeApp (TypeApp t argTy) retTy) = do   t =?= tyFunction   Just moduleName <- checkCurrentModule <$> get-  ret' <- makeBindingGroupVisible $ bindLocalVariables moduleName [(arg, argTy, Defined)] $ check ret retTy+  ret' <- withBindingGroupVisible $ bindLocalVariables moduleName [(arg, argTy, Defined)] $ check ret retTy   return $ TypedValue True (Abs (Left arg) ret') ty check' (Abs (Right _) _) _ = error "Binder was not desugared" check' (App f arg) ret = do
tests/Main.hs view
@@ -35,21 +35,21 @@   text <- readFile inputFile   return (inputFile, text) -loadPrelude :: Either String (String, String, P.Environment)+loadPrelude :: Either P.MultipleErrors (String, String, P.Environment) loadPrelude =   case P.parseModulesFromFiles id [("", P.prelude)] of-    Left parseError -> Left (show parseError)+    Left parseError -> Left . P.errorMessage . P.ErrorParsingPrelude $ parseError     Right ms -> runReaderT (P.compile (map snd ms) []) $ P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] } -compile :: P.Options P.Compile -> [FilePath] -> IO (Either String (String, String, P.Environment))+compile :: P.Options P.Compile -> [FilePath] -> IO (Either P.MultipleErrors (String, String, P.Environment)) compile opts inputFiles = do   modules <- P.parseModulesFromFiles id <$> readInput inputFiles   case modules of     Left parseError ->-      return (Left $ show parseError)+      return . Left . P.errorMessage . P.ErrorParsingPrelude $ parseError     Right ms -> return $ runReaderT (P.compile (map snd ms) []) opts -assert :: FilePath -> P.Options P.Compile -> FilePath -> (Either String (String, String, P.Environment) -> IO (Maybe String)) -> IO ()+assert :: FilePath -> P.Options P.Compile -> FilePath -> (Either P.MultipleErrors (String, String, P.Environment) -> IO (Maybe String)) -> IO () assert preludeExterns opts inputFile f = do   e <- compile opts [preludeExterns, inputFile]   maybeErr <- f e@@ -64,7 +64,7 @@                               { P.optionsMain = Just "Main"                               , P.optionsAdditional = P.CompileOptions "Tests" ["Main"] ["Main"]                               }-  assert preludeExterns options inputFile $ either (return . Just) $ \(js, _, _) -> do+  assert preludeExterns options inputFile $ either (return . Just . P.prettyPrintMultipleErrors False) $ \(js, _, _) -> do     process <- findNodeProcess     result <- traverse (\node -> readProcessWithExitCode node [] (preludeJs ++ js)) process     case result of@@ -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 err -> putStrLn err >> return Nothing+      Left errs -> putStrLn  (P.prettyPrintMultipleErrors False errs) >> return Nothing       Right _ -> return $ Just "Should not have compiled"  findNodeProcess :: IO (Maybe String)@@ -88,7 +88,7 @@ main = do   putStrLn "Compiling Prelude"   case loadPrelude of-    Left err -> putStrLn err >> exitFailure+    Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure     Right (preludeJs, exts, _) -> do       tmp <- getTemporaryDirectory       let preludeExterns = tmp ++ pathSeparator : "prelude.externs"@@ -105,4 +105,3 @@       forM_ failingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $         assertDoesNotCompile preludeExterns (failing ++ pathSeparator : inputFile)       exitSuccess-