@@ -40,48 +40,95 @@ import qualified Paths_purescript as Paths
4040import qualified System.IO.UTF8 as U (readFile)
4141import qualified Text.Parsec as Parsec (Parsec, eof)
4242
43+-- |
44+-- The PSCI state.
45+-- Holds a list of imported modules, loaded files, and partial let bindings.
46+-- The let bindings are partial,
47+-- because it makes more sense to apply the binding to the final evaluated expression.
48+--
4349data PSCI = PSCI [P.ProperName] [P.Module] [P.Value -> P.Value]
4450
4551-- State helpers
52+
53+-- |
54+-- Synonym to be more descriptive.
55+-- This is just @lift@
56+--
4657inputTToState :: InputT IO a -> StateT PSCI (InputT IO) a
4758inputTToState = lift
4859
60+-- |
61+-- Synonym to be more descriptive.
62+-- This is just @lift . lift@
63+--
4964ioToState :: IO a -> StateT PSCI (InputT IO) a
5065ioToState = lift . lift
5166
67+-- |
68+-- Updates the state to have more imported modules.
69+--
5270updateImports :: String -> PSCI -> PSCI
5371updateImports name (PSCI i m b) = PSCI (i ++ [P.ProperName name]) m b
5472
73+-- |
74+-- Updates the state to have more loaded files.
75+--
5576updateModules :: [P.Module] -> PSCI -> PSCI
5677updateModules modules (PSCI i m b) = PSCI i (m ++ modules) b
5778
79+-- |
80+-- Updates the state to have more let bindings.
81+--
5882updateLets :: (P.Value -> P.Value) -> PSCI -> PSCI
5983updateLets name (PSCI i m b) = PSCI i m (b ++ [name])
6084
6185-- File helpers
86+-- |
87+-- Load the necessary modules.
88+--
6289defaultImports :: [P.ProperName]
63−defaultImports = [P.ProperName "Prelude", P.ProperName "Eff"]
90+defaultImports = [P.ProperName "Prelude"]
6491
92+-- |
93+-- Locates the node executable.
94+-- Checks for either @nodejs@ or @node@.
95+--
6596findNodeProcess :: IO (Maybe String)
6697findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
6798 where names = ["nodejs", "node"]
6899
100+-- |
101+-- Grabs the filename where the history is stored.
102+--
69103getHistoryFilename :: IO FilePath
70104getHistoryFilename = getUserConfigFile "purescript" "psci_history"
71105
106+-- |
107+-- Grabs the filename where prelude is.
108+--
72109getPreludeFilename :: IO FilePath
73110getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
74111
112+-- |
113+-- Loads a file for use with imports.
114+--
75115loadModule :: FilePath -> IO (Either String [P.Module])
76116loadModule moduleFile = do
77117 moduleText <- U.readFile moduleFile
78118 return . either (Left . show) Right $ P.runIndentParser "" P.parseModules moduleText
79119
80120-- Messages
121+
122+-- |
123+-- The help message.
124+--
81125helpMessage :: String
82126helpMessage = "The following commands are available:\n\n " ++
83127 intercalate "\n " (map (intercalate " ") help)
84128
129+-- |
130+-- The welcome prologue.
131+--
85132prologueMessage :: String
86133prologueMessage = intercalate "\n"
87134 [ " ____ ____ _ _ "
@@ -96,10 +143,17 @@ prologueMessage = intercalate "\n"
96143 , "Expressions are terminated using Ctrl+D"
97144 ]
98145
146+-- |
147+-- The quit message.
148+--
99149quitMessage :: String
100150quitMessage = "See ya!"
101151
102152-- Haskeline completions
153+
154+-- |
155+-- Loads module, function, and file completions.
156+--
103157completion :: [P.Module] -> CompletionFunc IO
104158completion ms = completeWord Nothing " \t\n\r" findCompletions
105159 where
@@ -119,9 +173,15 @@ completion ms = completeWord Nothing " \t\n\r" findCompletions
119173 getDeclName _ = Nothing
120174
121175-- Compilation
176+
177+-- | Compilation options.
178+--
122179options :: P.Options
123180options = P.Options True False True (Just "Main") True "PS" []
124181
182+-- |
183+-- Makes a volatile module to execute the current expression.
184+--
125185createTemporaryModule :: [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
126186createTemporaryModule imports lets value =
127187 let
@@ -134,6 +194,9 @@ createTemporaryModule imports lets value =
134194 in
135195 P.Module moduleName $ map (importDecl . P.ModuleName . return) imports ++ [mainDecl]
136196
197+-- |
198+-- Takes a value declaration and evaluates it with the current state.
199+--
137200handleDeclaration :: P.Value -> PSCI -> InputT IO ()
138201handleDeclaration value (PSCI imports loadedModules lets) = do
139202 let m = createTemporaryModule imports lets value
@@ -148,14 +211,27 @@ handleDeclaration value (PSCI imports loadedModules lets) = do
148211 Nothing -> outputStrLn "Couldn't find node.js"
149212
150213-- Parser helpers
214+
215+-- |
216+-- Parser for our PSCI version of @let@.
217+-- This is essentially let from do-notation.
218+-- However, since we don't support the @Eff@ monad, we actually want the normal @let@.
219+--
151220parseLet :: Parsec.Parsec String P.ParseState (P.Value -> P.Value)
152221parseLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
153222 <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
154223
224+-- |
225+-- Parser for any other valid expression.
226+--
155227parseExpression :: Parsec.Parsec String P.ParseState P.Value
156228parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
157229
158230-- Commands
231+
232+-- |
233+-- Performs an action for each meta-command given, and also for expressions..
234+--
159235handleCommand :: Command -> StateT PSCI (InputT IO) ()
160236handleCommand Empty = return ()
161237handleCommand (Expression ls) =
@@ -177,6 +253,9 @@ handleCommand Reload = do
177253 put (PSCI defaultImports prelude [])
178254handleCommand Unknown = inputTToState $ outputStrLn "Unknown command"
179255
256+-- |
257+-- The PSCI main loop.
258+--
180259main :: IO ()
181260main = do
182261 preludeFilename <- getPreludeFilename