Created
December 31, 2019 16:50
-
-
Save sogaiu/02dc05c5b679199f96ef8d21c2365e87 to your computer and use it in GitHub Desktop.
clojure.main/repl using system classloader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; modified clojure.main | |
;; Copyright (c) Rich Hickey All rights reserved. The use and | |
;; distribution terms for this software are covered by the Eclipse Public | |
;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can be found | |
;; in the file epl-v10.html at the root of this distribution. By using this | |
;; software in any fashion, you are agreeing to be bound by the terms of | |
;; this license. You must not remove this notice, or any other, from this | |
;; software. | |
;; Originally contributed by Stephen C. Gilardi | |
(ns ^{:doc "Top-level main function for Clojure REPL and scripts." | |
:author "Stephen C. Gilardi and Rich Hickey"} | |
clojure-javaagent.cm | |
(:require | |
[clojure.main :as cm]) | |
(:import (clojure.lang LineNumberingPushbackReader LispReader$ReaderException))) | |
(defn repl | |
"Generic, reusable, read-eval-print loop. By default, reads from *in*, | |
writes to *out*, and prints exception summaries to *err*. If you use the | |
default :read hook, *in* must either be an instance of | |
LineNumberingPushbackReader or duplicate its behavior of both supporting | |
.unread and collapsing CR, LF, and CRLF into a single \\newline. Options | |
are sequential keyword-value pairs. Available options and their defaults: | |
- :init, function of no arguments, initialization hook called with | |
bindings for set!-able vars in place. | |
default: #() | |
- :need-prompt, function of no arguments, called before each | |
read-eval-print except the first, the user will be prompted if it | |
returns true. | |
default: (if (instance? LineNumberingPushbackReader *in*) | |
#(.atLineStart *in*) | |
#(identity true)) | |
- :prompt, function of no arguments, prompts for more input. | |
default: repl-prompt | |
- :flush, function of no arguments, flushes output | |
default: flush | |
- :read, function of two arguments, reads from *in*: | |
- returns its first argument to request a fresh prompt | |
- depending on need-prompt, this may cause the repl to prompt | |
before reading again | |
- returns its second argument to request an exit from the repl | |
- else returns the next object read from the input stream | |
default: repl-read | |
- :eval, function of one argument, returns the evaluation of its | |
argument | |
default: eval | |
- :print, function of one argument, prints its argument to the output | |
default: prn | |
- :caught, function of one argument, a throwable, called when | |
read, eval, or print throws an exception or error | |
default: repl-caught" | |
[& options] | |
(let [cl (ClassLoader/getSystemClassLoader)] | |
(.setContextClassLoader (Thread/currentThread) (clojure.lang.DynamicClassLoader. cl))) | |
(let [{:keys [init need-prompt prompt flush read eval print caught] | |
:or {init #() | |
need-prompt (if (instance? LineNumberingPushbackReader *in*) | |
#(.atLineStart ^LineNumberingPushbackReader *in*) | |
#(identity true)) | |
prompt cm/repl-prompt | |
flush flush | |
read cm/repl-read | |
eval eval | |
print prn | |
caught cm/repl-caught}} | |
(apply hash-map options) | |
request-prompt (Object.) | |
request-exit (Object.) | |
read-eval-print | |
(fn [] | |
(try | |
(let [read-eval *read-eval* | |
input (try | |
(cm/with-read-known (read request-prompt request-exit)) | |
(catch LispReader$ReaderException e | |
(throw (ex-info nil {:clojure.error/phase :read-source} e))))] | |
(or (#{request-prompt request-exit} input) | |
(let [value (binding [*read-eval* read-eval] (eval input))] | |
(set! *3 *2) | |
(set! *2 *1) | |
(set! *1 value) | |
(try | |
(print value) | |
(catch Throwable e | |
(throw (ex-info nil {:clojure.error/phase :print-eval-result} e))))))) | |
(catch Throwable e | |
(caught e) | |
(set! *e e))))] | |
(cm/with-bindings | |
(try | |
(init) | |
(catch Throwable e | |
(caught e) | |
(set! *e e))) | |
(prompt) | |
(flush) | |
(loop [] | |
(when-not | |
(try (identical? (read-eval-print) request-exit) | |
(catch Throwable e | |
(caught e) | |
(set! *e e) | |
nil)) | |
(when (need-prompt) | |
(prompt) | |
(flush)) | |
(recur)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment