1
1
{-# LANGUAGE DataKinds #-}
2
2
{-# LANGUAGE DeriveAnyClass #-}
3
3
{-# LANGUAGE DeriveGeneric #-}
4
+ {-# LANGUAGE LambdaCase #-}
4
5
{-# LANGUAGE OverloadedStrings #-}
5
6
{-# LANGUAGE TupleSections #-}
6
7
7
8
module Main (main ) where
8
9
9
- import Control.Monad (unless )
10
+ import Control.Monad (unless , (>=>) )
11
+ import Control.Monad.Error.Class (throwError )
10
12
import Control.Monad.IO.Class (liftIO )
11
13
import Control.Monad.Logger (runLogger' )
14
+ import Control.Monad.State (State )
15
+ import qualified Control.Monad.State as State
12
16
import Control.Monad.Trans (lift )
13
- import Control.Monad.Error.Class (throwError )
14
17
import Control.Monad.Trans.Except (ExceptT (.. ), runExceptT )
15
18
import Control.Monad.Trans.Reader (runReaderT )
16
19
import qualified Data.Aeson as A
17
20
import Data.Aeson ((.=) )
18
21
import qualified Data.ByteString.Lazy as BL
19
- import Data.List (foldl' )
22
+ import Data.Function (on )
23
+ import Data.List (foldl' , nubBy )
24
+ import qualified Data.Map as M
20
25
import Data.String (fromString )
21
26
import Data.Text (Text )
22
27
import qualified Data.Text as T
@@ -30,12 +35,14 @@ import qualified Language.PureScript.CodeGen.JS as J
30
35
import qualified Language.PureScript.CoreFn as CF
31
36
import qualified Language.PureScript.Errors.JSON as P
32
37
import qualified Language.PureScript.Interactive as I
38
+ import qualified Language.PureScript.TypeChecker.TypeSearch as TS
33
39
import System.Environment (getArgs )
34
40
import System.Exit (exitFailure )
35
41
import System.FilePath ((</>) )
36
42
import System.FilePath.Glob (glob )
37
43
import qualified System.IO as IO
38
44
import System.IO.UTF8 (readUTF8File )
45
+ import qualified Text.Parsec.Combinator as Parsec
39
46
import Web.Scotty
40
47
import qualified Web.Scotty as Scotty
41
48
@@ -90,6 +97,58 @@ server bundled externs initEnv port = do
90
97
Scotty. json $ A. object [ " error" .= err ]
91
98
Right comp ->
92
99
Scotty. json $ A. object [ " js" .= comp ]
100
+ get " /search" $ do
101
+ query <- param " q"
102
+ Scotty. setHeader " Access-Control-Allow-Origin" " *"
103
+ Scotty. setHeader " Content-Type" " application/json"
104
+ case tryParseType query of
105
+ Nothing -> Scotty. json $ A. object [ " error" .= (" Cannot parse type" :: Text ) ]
106
+ Just ty -> do
107
+ let elabs = lookupAllConstructors initEnv ty
108
+ search = M. toList . TS. typeSearch (Just [] ) initEnv (P. emptyCheckState initEnv)
109
+ results = nubBy ((==) `on` fst ) $ do
110
+ elab <- elabs
111
+ let strictMatches = search (replaceTypeVariablesAndDesugar (\ nm s -> P. Skolem nm s (P. SkolemScope 0 ) Nothing ) elab)
112
+ flexMatches = search (replaceTypeVariablesAndDesugar (const P. TUnknown ) elab)
113
+ take 50 (strictMatches ++ flexMatches)
114
+ Scotty. json $ A. object [ " results" .= [ P. showQualified P. runIdent k
115
+ | (k, _) <- take 50 results
116
+ ]
117
+ ]
118
+
119
+ lookupAllConstructors :: P. Environment -> P. Type -> [P. Type ]
120
+ lookupAllConstructors env = P. everywhereOnTypesM $ \ case
121
+ P. TypeConstructor (P. Qualified Nothing tyCon) -> P. TypeConstructor <$> lookupConstructor env tyCon
122
+ other -> pure other
123
+ where
124
+ lookupConstructor :: P. Environment -> P. ProperName 'P.TypeName -> [P. Qualified (P. ProperName 'P.TypeName )]
125
+ lookupConstructor env nm =
126
+ [ q
127
+ | (q@ (P. Qualified (Just mn) thisNm), _) <- M. toList (P. types env)
128
+ , thisNm == nm
129
+ ]
130
+
131
+ -- | (Consistently) replace unqualified type constructors and type variables with unknowns.
132
+ --
133
+ -- Also remove the @ParensInType@ Constructor (we need to deal with type operators later at some point).
134
+ replaceTypeVariablesAndDesugar :: (Text -> Int -> P. Type ) -> P. Type -> P. Type
135
+ replaceTypeVariablesAndDesugar f ty = State. evalState (P. everywhereOnTypesM go ty) (0 , M. empty) where
136
+ go = \ case
137
+ P. ParensInType ty -> pure ty
138
+ P. TypeVar s -> do
139
+ (next, m) <- State. get
140
+ case M. lookup s m of
141
+ Nothing -> do
142
+ let ty = f s next
143
+ State. put (next + 1 , M. insert s ty m)
144
+ pure ty
145
+ Just ty -> pure ty
146
+ other -> pure other
147
+
148
+ tryParseType :: Text -> Maybe P. Type
149
+ tryParseType = hush (P. lex " " ) >=> hush (P. runTokenParser " " (P. parsePolyType <* Parsec. eof))
150
+ where
151
+ hush f = either (const Nothing ) Just . f
93
152
94
153
bundle :: IO (Either Bundle. ErrorMessage String )
95
154
bundle = runExceptT $ do
0 commit comments