summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--autoload.c1
-rw-r--r--eval.c1
-rw-r--r--parser.c48
-rw-r--r--parser.h2
-rw-r--r--stdlib/getput.tl17
-rw-r--r--tests/018/getput.tl33
-rw-r--r--txr.175
7 files changed, 169 insertions, 8 deletions
diff --git a/autoload.c b/autoload.c
index 2b2b8f27..6d6deb4a 100644
--- a/autoload.c
+++ b/autoload.c
@@ -464,6 +464,7 @@ static val getput_set_entries(val fun)
val name[] = {
lit("get-jsons"), lit("put-jsons"),
lit("file-get"), lit("file-put"), lit("file-append"),
+ lit("file-get-objects"), lit("file-put-objects"), lit("file-append-objects"),
lit("file-get-string"), lit("file-put-string"), lit("file-append-string"),
lit("file-get-lines"), lit("file-put-lines"), lit("file-append-lines"),
lit("file-get-buf"), lit("file-put-buf"),
diff --git a/eval.c b/eval.c
index 72635252..26f4b701 100644
--- a/eval.c
+++ b/eval.c
@@ -7436,6 +7436,7 @@ void eval_init(void)
reg_fun(intern(lit("lisp-parse"), user_package), func_n5o(nread, 0));
reg_fun(intern(lit("read"), user_package), func_n5o(nread, 0));
reg_fun(intern(lit("iread"), user_package), func_n5o(iread, 0));
+ reg_fun(intern(lit("read-objects"), user_package), func_n5o(read_objects, 0));
reg_fun(intern(lit("get-json"), user_package), func_n5o(get_json, 0));
reg_fun(intern(lit("txr-parse"), user_package), func_n4o(txr_parse, 0));
reg_fun(intern(lit("load"), user_package), func_n1v(loadv));
diff --git a/parser.c b/parser.c
index b1397576..a5b3724e 100644
--- a/parser.c
+++ b/parser.c
@@ -891,21 +891,31 @@ val read_compiled_file(val self, val stream, val error_stream)
return read_file_common(self, stream, error_stream, t);
}
-val read_objects_from_string(val string, val error_stream,
- val error_return_val, val name_in)
+static val read_objects_common(val stream, val error_stream_in,
+ val error_return_val, val name,
+ val lineno, val self)
{
- val self = lit("read-objects-from-string");
- val stream = make_string_byte_input_stream(string);
- val name = default_arg(name_in, lit("string"));
+ val error_stream = if3(error_stream_in == t,
+ std_output,
+ default_arg_strict(error_stream_in, std_null));
val parser = ensure_parser(stream, name);
+ parser_t *pi = parser_get_impl(self, parser);
list_collect_decl (out, ptail);
+ if (lineno && !missingp(lineno))
+ pi->lineno = c_num(lineno, self);
+
for (;;) {
val form = lisp_parse_impl(self, prime_lisp, t, stream,
error_stream, unique_s, name, colon_k);
if (form == unique_s) {
- if (parser_errors(parser) != zero)
+ if (pi->syntax_tree == nao)
+ break;
+ if (pi->errors)
+ if (missingp(error_return_val))
+ uw_throwf(syntax_error_s, lit("read: ~a: errors encountered"),
+ name, nao);
return error_return_val;
break;
}
@@ -916,6 +926,32 @@ val read_objects_from_string(val string, val error_stream,
return out;
}
+val read_objects_from_string(val string, val error_stream,
+ val error_return_val, val name_in)
+{
+ val self = lit("read-objects-from-string");
+ val stream = make_string_byte_input_stream(string);
+ val name = default_arg(name_in, lit("string"));
+
+ return read_objects_common(stream, error_stream, error_return_val,
+ name, one, self);
+}
+
+val read_objects(val source_in, val error_stream, val error_return_val,
+ val name_in, val lineno_in)
+{
+ val self = lit("read-objects");
+ val source = default_arg_strict(source_in, std_input);
+ val str = stringp(source);
+ val input_stream = if3(str, make_string_byte_input_stream(source), source);
+ val name = default_arg_strict(name_in,
+ if3(str,
+ lit("string"),
+ stream_get_prop(input_stream, name_k)));
+ return read_objects_common(input_stream, error_stream, error_return_val,
+ name, lineno_in, self);
+}
+
val txr_parse(val source_in, val error_stream,
val error_return_val, val name_in)
{
diff --git a/parser.h b/parser.h
index fe05b448..09939fca 100644
--- a/parser.h
+++ b/parser.h
@@ -139,6 +139,8 @@ val read_eval_stream(val self, val stream, val error_stream);
val read_compiled_file(val self, val stream, val error_stream);
val read_objects_from_string(val string, val error_stream,
val error_return_val, val name_in);
+val read_objects(val source_in, val error_stream, val error_return_val,
+ val name_in, val lineno_in);
val txr_parse(val source, val error_stream,
val error_return_val, val name_in);
val repl(val bindings, val in_stream, val out_stream, val env);
diff --git a/stdlib/getput.tl b/stdlib/getput.tl
index fd62f911..8bc30598 100644
--- a/stdlib/getput.tl
+++ b/stdlib/getput.tl
@@ -62,6 +62,11 @@
(put-jsonl obj s flat-p))
t)
+(defun put-objects (list : (s *stdout*))
+ (each ((obj list))
+ (prinl obj s)
+ t))
+
(defun file-get (name : mopt)
(with-stream (s (open-file name `r@mopt`))
(read s)))
@@ -74,6 +79,18 @@
(with-stream (s (open-file name `a@mopt`))
(prinl obj s)))
+(defun file-get-objects (name : mopt (err-stream :))
+ (with-stream (s (open-file name `r@mopt`))
+ (read-objects s err-stream)))
+
+(defun file-put-objects (name seq : mopt)
+ (with-stream (s (open-file name `w@mopt`))
+ (put-objects seq s)))
+
+(defun file-append-objects (name seq : mopt)
+ (with-stream (s (open-file name `a@mopt`))
+ (put-objects seq s)))
+
(defun file-get-string (name : mopt)
(with-stream (s (open-file name `r@mopt`))
(get-string s)))
diff --git a/tests/018/getput.tl b/tests/018/getput.tl
new file mode 100644
index 00000000..7e8e2be1
--- /dev/null
+++ b/tests/018/getput.tl
@@ -0,0 +1,33 @@
+(load "../common")
+
+(defvarl file "getput.data")
+
+(push-after-load (remove-path file))
+
+(file-put-objects file '(1 2.3 (a . b) "foo"))
+
+(test
+ (file-get-lines file) ("1" "2.3" "(a . b)" "\"foo\""))
+
+(file-append-objects file '(#(nil)))
+
+(mtest
+ (file-get-lines file) ("1" "2.3" "(a . b)" "\"foo\"" "#(nil)")
+ (file-get-objects file) (1 2.3 (a . b) "foo" #(nil)))
+
+(mtest
+ (read-objects "(a . b) #\\c") ((a . b) #\c)
+ (read-objects "(a") :error)
+
+(file-put-string file "(a")
+
+(mtest
+ (file-get file) :error
+ (file-get-objects file) :error)
+
+(let ((errors (with-out-string-stream (err)
+ (ignerr (file-get-objects file : err)))))
+ (mtest
+ (true (contains "syntax error" errors)) t
+ (true (contains "unterminated" errors)) t
+ (true (contains ":1" errors)) t))
diff --git a/txr.1 b/txr.1
index 1c9e799a..a0776343 100644
--- a/txr.1
+++ b/txr.1
@@ -64828,6 +64828,28 @@ it may be useful to set
true in order to obtain better diagnostics. However, source location recording
incurs a performance and storage penalty.
+.coNP Function @ read-objects
+.synb
+.mets (read-objects >> [ source
+.mets \ \ \ \ \ \ \ \ \ \ \ \ \ \ >> [ err-stream
+.mets \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ >> [ err-retval >> [ name <> [ lineno ]]]]])
+.syne
+.desc
+The
+.code read-objects
+function has the same argument syntax and semantics as the
+.code read
+function, except that rather than reading one object, it reads all
+the Lisp objects from the source, and returns a list of these objects.
+
+If the stream is empty, then
+.code read-objects
+returns the empty list
+.codn nil ,
+whereas the
+.code read
+function treats the situation as an error.
+
.coNP Function @ parse-errors
.synb
.mets (parse-errors << stream )
@@ -65760,14 +65782,63 @@ and then close the stream.
These functions are close counterparts of, respectively,
.codn file-get ,
-.code file-append-string
+.code file-get-string
and
-.codn file-append-lines .
+.codn file-get-lines .
These functions behave differently when the indicated file
already exists. Rather than being truncated and overwritten,
the file is extended by appending the new data to its end.
+.coNP Function @ file-get-objects
+.synb
+.mets (file-get-objects < name < [ mode-opts <> [ error-stream ]])
+.syne
+.desc
+The
+.code file-get-objects
+function opens an input text stream over the file indicated by the
+.meta name
+argument, which is a string.
+
+All Lisp objects are read from the stream. Parse errors are
+reported to
+.meta error-stream
+which defaults to
+.code *stdnull*
+(error output is discarded).
+
+If there is a parse error, the function throws an exception,
+otherwise the list of parsed objects is returned.
+
+.coNP Functions @ file-put-objects and @ file-append-objects
+.synb
+.mets (file-put-objects < name < seq <> [ mode-opts ])
+.syne
+.desc
+The functions
+.code file-put-objects
+and
+.code file-append-objects
+open a text stream over the file indicated by the string argument
+.metn name ,
+and write each of the objects contained in sequence
+.meta seq
+into the stream as if using the
+.code prinl
+function on each individual element of
+.metn seq .
+
+The
+.code file-put-objects
+function opens the file using the
+.str w
+mode, which overwrites the file if it exists, whereas
+.code file-append-objects
+uses
+.strn a ,
+which appends to the file.
+
.coNP Functions @, command-get @ command-get-string and @ command-get-lines
.synb
.mets (command-get < cmd <> [ mode-opts ])