From 65f73e458b068d851833fec7846102f600438fed Mon Sep 17 00:00:00 2001 From: mitch-kyle Date: Wed, 21 Aug 2024 13:47:21 -0300 Subject: [PATCH 1/3] Add read-all function --- src/basilisp/contrib/nrepl_server.lpy | 13 ++---- src/basilisp/core.lpy | 66 +++++++++++++++------------ 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/basilisp/contrib/nrepl_server.lpy b/src/basilisp/contrib/nrepl_server.lpy index 2a75b9b61..f8d5f4b0f 100644 --- a/src/basilisp/contrib/nrepl_server.lpy +++ b/src/basilisp/contrib/nrepl_server.lpy @@ -122,7 +122,6 @@ [{:keys [client* code ns file _column _line] :as request} send-fn] (let [{:keys [*1 *2 *3 *e eval-ns]} @client* out-stream (StreamOutFn #(send-fn request {"out" %})) - reader (io/StringIO code) ctx (basilisp.lang.compiler.CompilerContext. (or file "")) eval-ns (if ns (create-ns (symbol ns)) @@ -134,13 +133,11 @@ *3 *3 *e *e] (try - (let [results (for [form (seq (basilisp.lang.reader/read reader - *resolver* - *data-readers*))] + (let [result (last + (for [form (read-all (io/StringIO code))] (basilisp.lang.compiler/compile-and-exec-form form ctx - *ns*)) - result (last results)] + *ns*)))] (send-value request send-fn [result {:ns (str *ns*)}])) (catch python/Exception e (debug :eval-exception e) @@ -183,9 +180,7 @@ [resolve-ns symbol-str] (let [reader (io/StringIO symbol-str) {:keys [form error]} (try {:form (binding [*ns* resolve-ns] - (first (seq (basilisp.lang.reader/read reader - *resolver* - *data-readers*))))} + (read reader))} (catch python/Exception e (debug :symbol-identify-reader-error :input symbol-str :exception e) {:error (str e)}))] diff --git a/src/basilisp/core.lpy b/src/basilisp/core.lpy index 9b697e4ef..a275c56a9 100644 --- a/src/basilisp/core.lpy +++ b/src/basilisp/core.lpy @@ -4428,6 +4428,17 @@ *resolver* basilisp.lang.runtime/resolve-alias) +(defn- read-iterator + [opts x] + (let [read (:read opts basilisp.lang.reader/read)] + (read x + *resolver* + *data-readers* + (:eof opts) + (= (:eof opts) :eofthrow) + (:features opts) + (not= :preserve (:read-cond opts))))) + (defn read-string "Read a string of Basilisp code. @@ -4440,17 +4451,7 @@ ([s] (read-string {:eof :eofthrow} s)) ([opts s] - (first (basilisp.lang.reader/read-str s - *resolver* - *data-readers* - (:eof opts) - (if (= (:eof opts) :eofthrow) - true - false) - (:features opts) - (if (= :preserve (:read-cond opts)) - false - true))))) + (first (read-iterator (assoc opts :read basilisp.lang.reader/read-str) s)))) (defn read "Read the next form from the ``stream``\\. If no stream is specified, uses the value @@ -4468,23 +4469,30 @@ ([stream] (read stream true nil)) ([opts stream] - (first (basilisp.lang.reader/read stream - *resolver* - *data-readers* - (:eof opts) - (if (= (:eof opts) :eofthrow) - true - false) - (:features opts) - (if (= :preserve (:read-cond opts)) - false - true)))) + (first (read-iterator opts stream))) ([stream eof-error? eof-value] - (first (basilisp.lang.reader/read stream - *resolver* - *data-readers* - eof-value - eof-error?)))) + (first (read-iterator {:eof (if eof-error? :eofthrow eof-value)} stream)))) + +(defn read-all + "Eagerly read all forms from the ``stream``\\. If no stream is specified, uses the + value currently bound to :lpy:var:`*in*`. + + Callers may bind a map of readers to :lpy:var:`*data-readers*` or a default data + reader function to :lpy:var::`*default-data-reader-fn*` to customize the data + readers used reading this string + + The stream must satisfy the interface of :external:py:class:`io.TextIOBase`\\, but + does not require any pushback capabilities. The default + ``basilisp.lang.reader.StreamReader`` can wrap any object implementing ``TextIOBase`` + and provide pushback capabilities." + ([stream] + (read-all nil stream)) + ([opts stream] + (let [eof (python/object)] + (->> (read-iterator (assoc opts :eof eof) stream) + seq + (take-while #(not (identical? % eof))) + doall)))) (defn eval "Evaluate a form (not a string) and return its result. @@ -4517,9 +4525,7 @@ (python/str)) ctx (basilisp.lang.compiler.CompilerContext. (or src ""))] (last - (for [form (seq (basilisp.lang.reader/read reader - *resolver* - *data-readers*))] + (for [form (seq (read-all reader))] (basilisp.lang.compiler/compile-and-exec-form form ctx *ns*))))) From 0a3d1c4bb7e5fcbd08ddfd8aac37c98ec0debf13 Mon Sep 17 00:00:00 2001 From: mitch-kyle Date: Wed, 21 Aug 2024 14:08:11 -0300 Subject: [PATCH 2/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcf1a087f..8037489aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * Added the `CollReduce` and `KVReduce` protocols in `basilisp.core.protocols` and implemented `reduce` in terms of those protocols (#927) * Added `basilisp.pprint/print-table` function (#983) + * Added `basilisp.core/read-all` function (#986) ### Changed * Improved on the nREPL server exception messages by matching that of the REPL user friendly format (#968) From c399878ddf22c0fd1e0e3171440317cd6480db84 Mon Sep 17 00:00:00 2001 From: Mitch Kyle Date: Wed, 21 Aug 2024 14:39:36 -0300 Subject: [PATCH 3/3] Update src/basilisp/core.lpy Co-authored-by: Chris Rink --- src/basilisp/core.lpy | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/basilisp/core.lpy b/src/basilisp/core.lpy index a275c56a9..7940a92ee 100644 --- a/src/basilisp/core.lpy +++ b/src/basilisp/core.lpy @@ -4477,9 +4477,8 @@ "Eagerly read all forms from the ``stream``\\. If no stream is specified, uses the value currently bound to :lpy:var:`*in*`. - Callers may bind a map of readers to :lpy:var:`*data-readers*` or a default data - reader function to :lpy:var::`*default-data-reader-fn*` to customize the data - readers used reading this string + Callers may bind a map of readers to :lpy:var:`*data-readers*` to customize + the data readers used reading this string The stream must satisfy the interface of :external:py:class:`io.TextIOBase`\\, but does not require any pushback capabilities. The default