git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
More documentation.
25d8cf1joneshf
psci/Main.hs+80−1
@@ -40,48 +40,95 @@ import qualified Paths_purescript as Paths
40import qualified System.IO.UTF8 as U (readFile)
40import qualified System.IO.UTF8 as U (readFile)
41import qualified Text.Parsec as Parsec (Parsec, eof)
41import qualified Text.Parsec as Parsec (Parsec, eof)
42
42
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+--
43data PSCI = PSCI [P.ProperName] [P.Module] [P.Value -> P.Value]
49data PSCI = PSCI [P.ProperName] [P.Module] [P.Value -> P.Value]
44
50
45-- State helpers
51-- State helpers
52+
53+-- |
54+-- Synonym to be more descriptive.
55+-- This is just @lift@
56+--
46inputTToState :: InputT IO a -> StateT PSCI (InputT IO) a
57inputTToState :: InputT IO a -> StateT PSCI (InputT IO) a
47inputTToState = lift
58inputTToState = lift
48
59
60+-- |
61+-- Synonym to be more descriptive.
62+-- This is just @lift . lift@
63+--
49ioToState :: IO a -> StateT PSCI (InputT IO) a
64ioToState :: IO a -> StateT PSCI (InputT IO) a
50ioToState = lift . lift
65ioToState = lift . lift
51
66
67+-- |
68+-- Updates the state to have more imported modules.
69+--
52updateImports :: String -> PSCI -> PSCI
70updateImports :: String -> PSCI -> PSCI
53updateImports name (PSCI i m b) = PSCI (i ++ [P.ProperName name]) m b
71updateImports name (PSCI i m b) = PSCI (i ++ [P.ProperName name]) m b
54
72
73+-- |
74+-- Updates the state to have more loaded files.
75+--
55updateModules :: [P.Module] -> PSCI -> PSCI
76updateModules :: [P.Module] -> PSCI -> PSCI
56updateModules modules (PSCI i m b) = PSCI i (m ++ modules) b
77updateModules modules (PSCI i m b) = PSCI i (m ++ modules) b
57
78
79+-- |
80+-- Updates the state to have more let bindings.
81+--
58updateLets :: (P.Value -> P.Value) -> PSCI -> PSCI
82updateLets :: (P.Value -> P.Value) -> PSCI -> PSCI
59updateLets name (PSCI i m b) = PSCI i m (b ++ [name])
83updateLets name (PSCI i m b) = PSCI i m (b ++ [name])
60
84
61-- File helpers
85-- File helpers
86+-- |
87+-- Load the necessary modules.
88+--
62defaultImports :: [P.ProperName]
89defaultImports :: [P.ProperName]
63−defaultImports = [P.ProperName "Prelude", P.ProperName "Eff"]
90+defaultImports = [P.ProperName "Prelude"]
64
91
92+-- |
93+-- Locates the node executable.
94+-- Checks for either @nodejs@ or @node@.
95+--
65findNodeProcess :: IO (Maybe String)
96findNodeProcess :: IO (Maybe String)
66findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
97findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
67 where names = ["nodejs", "node"]
98 where names = ["nodejs", "node"]
68
99
100+-- |
101+-- Grabs the filename where the history is stored.
102+--
69getHistoryFilename :: IO FilePath
103getHistoryFilename :: IO FilePath
70getHistoryFilename = getUserConfigFile "purescript" "psci_history"
104getHistoryFilename = getUserConfigFile "purescript" "psci_history"
71
105
106+-- |
107+-- Grabs the filename where prelude is.
108+--
72getPreludeFilename :: IO FilePath
109getPreludeFilename :: IO FilePath
73getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
110getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
74
111
112+-- |
113+-- Loads a file for use with imports.
114+--
75loadModule :: FilePath -> IO (Either String [P.Module])
115loadModule :: FilePath -> IO (Either String [P.Module])
76loadModule moduleFile = do
116loadModule moduleFile = do
77 moduleText <- U.readFile moduleFile
117 moduleText <- U.readFile moduleFile
78 return . either (Left . show) Right $ P.runIndentParser "" P.parseModules moduleText
118 return . either (Left . show) Right $ P.runIndentParser "" P.parseModules moduleText
79
119
80-- Messages
120-- Messages
121+
122+-- |
123+-- The help message.
124+--
81helpMessage :: String
125helpMessage :: String
82helpMessage = "The following commands are available:\n\n " ++
126helpMessage = "The following commands are available:\n\n " ++
83 intercalate "\n " (map (intercalate " ") help)
127 intercalate "\n " (map (intercalate " ") help)
84
128
129+-- |
130+-- The welcome prologue.
131+--
85prologueMessage :: String
132prologueMessage :: String
86prologueMessage = intercalate "\n"
133prologueMessage = intercalate "\n"
87 [ " ____ ____ _ _ "
134 [ " ____ ____ _ _ "
@@ -96,10 +143,17 @@ prologueMessage = intercalate "\n"
96 , "Expressions are terminated using Ctrl+D"
143 , "Expressions are terminated using Ctrl+D"
97 ]
144 ]
98
145
146+-- |
147+-- The quit message.
148+--
99quitMessage :: String
149quitMessage :: String
100quitMessage = "See ya!"
150quitMessage = "See ya!"
101
151
102-- Haskeline completions
152-- Haskeline completions
153+
154+-- |
155+-- Loads module, function, and file completions.
156+--
103completion :: [P.Module] -> CompletionFunc IO
157completion :: [P.Module] -> CompletionFunc IO
104completion ms = completeWord Nothing " \t\n\r" findCompletions
158completion ms = completeWord Nothing " \t\n\r" findCompletions
105 where
159 where
@@ -119,9 +173,15 @@ completion ms = completeWord Nothing " \t\n\r" findCompletions
119 getDeclName _ = Nothing
173 getDeclName _ = Nothing
120
174
121-- Compilation
175-- Compilation
176+
177+-- | Compilation options.
178+--
122options :: P.Options
179options :: P.Options
123options = P.Options True False True (Just "Main") True "PS" []
180options = P.Options True False True (Just "Main") True "PS" []
124
181
182+-- |
183+-- Makes a volatile module to execute the current expression.
184+--
125createTemporaryModule :: [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
185createTemporaryModule :: [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
126createTemporaryModule imports lets value =
186createTemporaryModule imports lets value =
127 let
187 let
@@ -134,6 +194,9 @@ createTemporaryModule imports lets value =
134 in
194 in
135 P.Module moduleName $ map (importDecl . P.ModuleName . return) imports ++ [mainDecl]
195 P.Module moduleName $ map (importDecl . P.ModuleName . return) imports ++ [mainDecl]
136
196
197+-- |
198+-- Takes a value declaration and evaluates it with the current state.
199+--
137handleDeclaration :: P.Value -> PSCI -> InputT IO ()
200handleDeclaration :: P.Value -> PSCI -> InputT IO ()
138handleDeclaration value (PSCI imports loadedModules lets) = do
201handleDeclaration value (PSCI imports loadedModules lets) = do
139 let m = createTemporaryModule imports lets value
202 let m = createTemporaryModule imports lets value
@@ -148,14 +211,27 @@ handleDeclaration value (PSCI imports loadedModules lets) = do
148 Nothing -> outputStrLn "Couldn't find node.js"
211 Nothing -> outputStrLn "Couldn't find node.js"
149
212
150-- Parser helpers
213-- 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+--
151parseLet :: Parsec.Parsec String P.ParseState (P.Value -> P.Value)
220parseLet :: Parsec.Parsec String P.ParseState (P.Value -> P.Value)
152parseLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
221parseLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
153 <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
222 <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
154
223
224+-- |
225+-- Parser for any other valid expression.
226+--
155parseExpression :: Parsec.Parsec String P.ParseState P.Value
227parseExpression :: Parsec.Parsec String P.ParseState P.Value
156parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
228parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
157
229
158-- Commands
230-- Commands
231+
232+-- |
233+-- Performs an action for each meta-command given, and also for expressions..
234+--
159handleCommand :: Command -> StateT PSCI (InputT IO) ()
235handleCommand :: Command -> StateT PSCI (InputT IO) ()
160handleCommand Empty = return ()
236handleCommand Empty = return ()
161handleCommand (Expression ls) =
237handleCommand (Expression ls) =
@@ -177,6 +253,9 @@ handleCommand Reload = do
177 put (PSCI defaultImports prelude [])
253 put (PSCI defaultImports prelude [])
178handleCommand Unknown = inputTToState $ outputStrLn "Unknown command"
254handleCommand Unknown = inputTToState $ outputStrLn "Unknown command"
179
255
256+-- |
257+-- The PSCI main loop.
258+--
180main :: IO ()
259main :: IO ()
181main = do
260main = do
182 preludeFilename <- getPreludeFilename
261 preludeFilename <- getPreludeFilename