11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE DeriveAnyClass #-}
33{-# LANGUAGE DeriveGeneric #-}
4+ {-# LANGUAGE LambdaCase #-}
45{-# LANGUAGE OverloadedStrings #-}
56{-# LANGUAGE TupleSections #-}
67
78module Main (main ) where
89
9- import Control.Monad (unless )
10+ import Control.Monad (unless , (>=>) )
11+ import Control.Monad.Error.Class (throwError )
1012import Control.Monad.IO.Class (liftIO )
1113import Control.Monad.Logger (runLogger' )
14+ import Control.Monad.State (State )
15+ import qualified Control.Monad.State as State
1216import Control.Monad.Trans (lift )
13- import Control.Monad.Error.Class (throwError )
1417import Control.Monad.Trans.Except (ExceptT (.. ), runExceptT )
1518import Control.Monad.Trans.Reader (runReaderT )
1619import qualified Data.Aeson as A
1720import Data.Aeson ((.=) )
1821import qualified Data.ByteString.Lazy as BL
1922import Data.List (foldl' )
23+ import qualified Data.Map as M
2024import Data.String (fromString )
2125import Data.Text (Text )
2226import qualified Data.Text as T
@@ -30,12 +34,14 @@ import qualified Language.PureScript.CodeGen.JS as J
3034import qualified Language.PureScript.CoreFn as CF
3135import qualified Language.PureScript.Errors.JSON as P
3236import qualified Language.PureScript.Interactive as I
37+ import qualified Language.PureScript.TypeChecker.TypeSearch as TS
3338import System.Environment (getArgs )
3439import System.Exit (exitFailure )
3540import System.FilePath ((</>) )
3641import System.FilePath.Glob (glob )
3742import qualified System.IO as IO
3843import System.IO.UTF8 (readUTF8File )
44+ import qualified Text.Parsec.Combinator as Parsec
3945import Web.Scotty
4046import qualified Web.Scotty as Scotty
4147
@@ -90,6 +96,47 @@ server bundled externs initEnv port = do
9096 Scotty. json $ A. object [ " error" .= err ]
9197 Right comp ->
9298 Scotty. json $ A. object [ " js" .= comp ]
99+ get " /search" $ do
100+ query <- param " q"
101+ case tryParseType query of
102+ Nothing -> Scotty. json $ A. object [ " error" .= (" Cannot parse type" :: Text ) ]
103+ Just ty -> do
104+ let ty' = replaceTypeVariablesAndDesugar ty
105+ let results = TS. typeSearch (Just [] ) initEnv (P. emptyCheckState initEnv) ty'
106+ Scotty. json $ A. object [ " results" .= A. object [ P. showQualified P. runIdent k .= P. prettyPrintType v
107+ | (k, v) <- take 20 (M. toList results)
108+ ]
109+ ]
110+
111+ -- | (Consistently) replace unqualified type constructors and type variables with unknowns.
112+ --
113+ -- Also remove the @ParensInType@ Constructor (we need to deal with type operators later at some point).
114+ replaceTypeVariablesAndDesugar :: P. Type -> P. Type
115+ replaceTypeVariablesAndDesugar ty = State. evalState (P. everywhereOnTypesM go ty) (0 , M. empty) where
116+ go = \ case
117+ P. ParensInType ty -> pure ty
118+ P. TypeConstructor (P. Qualified Nothing tyCon) -> do
119+ (next, m) <- State. get
120+ case M. lookup (Left tyCon) m of
121+ Nothing -> do
122+ let ty = P. TUnknown next
123+ State. put (next + 1 , M. insert (Left tyCon) ty m)
124+ pure ty
125+ Just ty -> pure ty
126+ P. TypeVar s -> do
127+ (next, m) <- State. get
128+ case M. lookup (Right s) m of
129+ Nothing -> do
130+ let ty = P. TUnknown next
131+ State. put (next + 1 , M. insert (Right s) ty m)
132+ pure ty
133+ Just ty -> pure ty
134+ other -> pure other
135+
136+ tryParseType :: Text -> Maybe P. Type
137+ tryParseType = hush (P. lex " " ) >=> hush (P. runTokenParser " " (P. parsePolyType <* Parsec. eof))
138+ where
139+ hush f = either (const Nothing ) Just . f
93140
94141bundle :: IO (Either Bundle. ErrorMessage String )
95142bundle = runExceptT $ do
0 commit comments