(.module: lux (lux (control [monad #+ do] ["ex" exception #+ exception:]) (data [maybe] ["e" error #+ Error] [text "text/" Equivalence] text/format (coll (dictionary ["dict" unordered]))) [macro] (lang [syntax #+ Aliases] (type [check]) [".L" init] [".L" module] [".L" scope] [".L" extension] (extension [".E" analysis])) (concurrency [promise] [task #+ Task]) [io] (world [file #+ File] [console #+ Console])) (luxc [lang] (lang [".L" host] [".L" translation] [".L" eval] (translation (jvm [".T" runtime])) (extension [".E" synthesis] [".E" translation] [".E" statement])))) (do-template [] [(exception: #export ( {message Text}) message)] [repl-initialization-failed] [repl-error] ) (def: repl-module "") (def: no-aliases Aliases (dict.new text.Hash)) (def: (initialize source-dirs target-dir console) (-> (List File) File Console (Task Lux)) (do promise.Monad [output (promise.future (do io.Monad [host hostL.init-host] (case (macro.run' (initL.compiler host) (moduleL.with-module +0 repl-module runtimeT.translate)) (#e.Success [compiler _]) (|> compiler (set@ [#.info #.mode] #.REPL) (set@ #.extensions (:coerce Nothing {#extensionL.analysis analysisE.defaults #extensionL.synthesis synthesisE.defaults #extensionL.translation translationE.defaults #extensionL.statement statementE.defaults})) (translationL.translate-module source-dirs target-dir translationL.prelude)) (#e.Error error) (wrap (#e.Error error)))))] (case output (#e.Success compiler) (do task.Monad [_ (console.write (format "\nWelcome to the REPL!\n" "Type \"exit\" to leave.\n\n") console)] (wrap compiler)) (#e.Error message) (task.throw repl-initialization-failed message)))) (def: (add-line line [where offset input]) (-> Text Source Source) [where offset (format input "\n" line)]) (def: (repl-translate source-dirs target-dir code) (-> (List File) File Code (Meta [Type Any])) (function (_ compiler) (case ((translationL.translate (translationL.translate-module source-dirs target-dir) no-aliases code) compiler) (#e.Success [compiler' aliases']) (#e.Success [compiler' [Nothing []]]) (#e.Error error) (if (ex.match? translationL.Unrecognized-Statement error) ((do macro.Monad [[var-id varT] (lang.with-type-env check.var) exprV (scopeL.with-scope repl-module (evalL.eval varT code)) ?exprT (lang.with-type-env (check.read var-id))] (wrap [(maybe.assume ?exprT) exprV])) compiler) (#e.Error error))))) (def: fresh-source Source [[repl-module +1 +0] +0 ""]) (def: #export (run source-dirs target-dir) (-> (List File) File (Task Any)) (do task.Monad [console (promise.future console.open) compiler (initialize source-dirs target-dir console)] (loop [compiler compiler source fresh-source multi-line? false] (do @ [_ (if multi-line? (console.write " " console) (console.write "> " console)) line (console.read-line console)] (if (text/= "exit" line) (console.write "Till next time..." console) (case (do e.Monad [[source' exprC] (syntax.read repl-module no-aliases (add-line line source))] (macro.run' compiler (lang.with-current-module repl-module (do macro.Monad [[exprT exprV] (repl-translate source-dirs target-dir exprC)] (wrap [source' exprT exprV]))))) (#e.Success [compiler' [source' exprT exprV]]) (do @ [_ (console.write (represent compiler' exprT exprV) console)] (recur compiler' source' false)) (#e.Error error) (if (ex.match? syntax.end-of-file error) (recur compiler source true) (exec (log! (ex.construct repl-error error)) (recur compiler fresh-source false)))))) )))