summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-12-11 07:21:04 -0800
committerKaz Kylheku <kaz@kylheku.com>2023-12-11 07:21:04 -0800
commit17f11d14178db6e8367ba598bc2e4a1f0fae4d59 (patch)
treea6d7ec8ffea761859ade6bdb447fc3ee29cbd4ed
parent2b896e09bdf71fb94e40a105b681c26938daa961 (diff)
downloadtxr-17f11d14178db6e8367ba598bc2e4a1f0fae4d59.tar.gz
txr-17f11d14178db6e8367ba598bc2e4a1f0fae4d59.tar.bz2
txr-17f11d14178db6e8367ba598bc2e4a1f0fae4d59.zip
load: load block value should be exit status.
When TXR executes a top-level program, such that it will exit when the last form in that program terminates, it simulates a load. There is a block named load visible, and the program can evaluate a (return-from load <expr>). The value of that <expr> is thrown away, and the termination status is always unsuccessful. In this patch, (return-from load <expr>) is made to work such that the value of <expr> will determine the exit status, according to the same interpretation that (exit <expr>) would give to the value. * sysif.[ch] (exit_wrap): Static function becomes external. * txr.c (txr_main): In the cases where we execute a file and return from main, we now call exit_wrap instead. The termination status is not simply based on whether the file was successfully read, but takes into account the load block. * tests/019/load-ret/{script.tl,bad.tl}: New files. * tests/019/load-ret/load-ret.tl: New tests. * txr.1: Documented.
-rw-r--r--sysif.c2
-rw-r--r--sysif.h1
-rw-r--r--tests/019/load-ret.tl10
-rw-r--r--tests/019/load-ret/bad.tl1
-rw-r--r--tests/019/load-ret/script.tl1
-rw-r--r--txr.122
-rw-r--r--txr.c15
7 files changed, 41 insertions, 11 deletions
diff --git a/sysif.c b/sysif.c
index b02ec607..6eedb011 100644
--- a/sysif.c
+++ b/sysif.c
@@ -220,7 +220,7 @@ static val daemon_wrap(val nochdir, val noclose)
}
#endif
-static val exit_wrap(val status)
+val exit_wrap(val status)
{
val self = lit("exit");
int stat;
diff --git a/sysif.h b/sysif.h
index 891cc091..13788c91 100644
--- a/sysif.h
+++ b/sysif.h
@@ -44,6 +44,7 @@ val env(void);
val replace_env(val env_list);
val getenv_wrap(val name);
val errno_to_str(int err);
+val exit_wrap(val status);
val at_exit_call(val func);
val at_exit_do_not_call(val func);
val usleep_wrap(val usec);
diff --git a/tests/019/load-ret.tl b/tests/019/load-ret.tl
index a79f7da9..1c99281f 100644
--- a/tests/019/load-ret.tl
+++ b/tests/019/load-ret.tl
@@ -11,3 +11,13 @@
(load-for (var abc "load-ret/module2" 'abc)) nil
(load-for (var abc "load-ret/module2" 'abc)
(var ghi "load-ret/module2" 'ghi 2 3 4)) 9)
+
+(defvarl here (dir-name self-path))
+
+(mtest
+ (sh `@{txr-exe-path} @here/load-ret/script.tl 0`) 0
+ (sh `@{txr-exe-path} @here/load-ret/script.tl 1`) 1
+ (sh `@{txr-exe-path} @here/load-ret/script.tl 7`) 7)
+
+(test
+ (sh `@{txr-exe-path} @here/load-ret/bad.tl 1 2> /dev/null`) 1)
diff --git a/tests/019/load-ret/bad.tl b/tests/019/load-ret/bad.tl
new file mode 100644
index 00000000..2d06f376
--- /dev/null
+++ b/tests/019/load-ret/bad.tl
@@ -0,0 +1 @@
+(
diff --git a/tests/019/load-ret/script.tl b/tests/019/load-ret/script.tl
new file mode 100644
index 00000000..8e13dabf
--- /dev/null
+++ b/tests/019/load-ret/script.tl
@@ -0,0 +1 @@
+(return-from load (toint [*args* 0]))
diff --git a/txr.1 b/txr.1
index 2cc3f8bf..4a83e358 100644
--- a/txr.1
+++ b/txr.1
@@ -82112,11 +82112,29 @@ expression. In this situation, the value of
.meta expr
will appear as the return value of the
.code load
-function. A block named
+function.
+
+When a \*(TL file, or compiled file, is executed from the \*(TX command line
+in such a way that \*(TX will terminate when that file's last form
+has been evaluated, then if that file performs a
+.code return-from
+the
+.code load
+block, the value of
+.meta expr
+will turn into the termination status in exactly the same way as if
+that value were used as an argument to the
+.code exit
+function. However, if \*(TX has been instructed to enter into the
+Listener after executing the file, then the value of
+.meta expr
+is discarded.
+
+A block named
.code load
is also established by the
.code @(load)
-directive in the pattern language, that that directive provides
+directive in the pattern language. That directive provides
no access to the returned value. The block is also visible to the
file processed from the command line. When a such a file aborts
the load via
diff --git a/txr.c b/txr.c
index 40e11ceb..78ea05b9 100644
--- a/txr.c
+++ b/txr.c
@@ -1261,26 +1261,25 @@ int txr_main(int argc, char **argv)
{
if (txr_lisp_p == chr('o')) {
- val result = nil;
uw_block_begin (load_s, ret);
- result = read_compiled_file_noerr(self, parse_stream, spec_file_str,
- std_error);
+ ret = read_compiled_file_noerr(self, parse_stream,
+ spec_file_str, std_error);
uw_block_end;
if (!enter_repl)
- return result ? 0 : EXIT_FAILURE;
+ exit_wrap(ret);
} else if (enter_repl) {
uw_block_begin (load_s, ret);
- read_eval_stream_noerr(self, parse_stream, spec_file_str, std_error);
+ ret = read_eval_stream_noerr(self, parse_stream,
+ spec_file_str, std_error);
uw_block_end;
close_stream(parse_stream, nil);
run_load_hooks(dyn_env);
uw_release_deferred_warnings();
} else {
- val result = nil;
uw_block_begin (load_s, ret);
- result = read_eval_stream(self, parse_stream, std_error);
+ ret = read_eval_stream(self, parse_stream, std_error);
uw_block_end;
- return result ? 0 : EXIT_FAILURE;
+ exit_wrap(ret);
}
}