Skip to content

Add read-all function #986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 4 additions & 9 deletions src/basilisp/contrib/nrepl_server.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<nREPL Input>"))
eval-ns (if ns
(create-ns (symbol ns))
Expand All @@ -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)
Expand Down Expand Up @@ -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)}))]
Expand Down
65 changes: 35 additions & 30 deletions src/basilisp/core.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -4468,23 +4469,29 @@
([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*` 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.
Expand Down Expand Up @@ -4517,9 +4524,7 @@
(python/str))
ctx (basilisp.lang.compiler.CompilerContext. (or src "<Load Input>"))]
(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*)))))
Expand Down
Loading