summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-05-01 21:31:45 -0700
committerKaz Kylheku <kaz@kylheku.com>2019-05-01 21:31:45 -0700
commit065dde19dfbe50e91e313e5b3ccc033cfbe47f74 (patch)
tree2ba6874a603e014b4be5e7e273eac2b62bae2ab5
parent488c1ba59416a0b2ce87a36d7df3026e334d66b9 (diff)
downloadtxr-065dde19dfbe50e91e313e5b3ccc033cfbe47f74.tar.gz
txr-065dde19dfbe50e91e313e5b3ccc033cfbe47f74.tar.bz2
txr-065dde19dfbe50e91e313e5b3ccc033cfbe47f74.zip
loading: try unsuffixed files directly last.
In this patch we change the strategy for resolving unsuffixed paths in load and @(load). In load, an unsuffixed name is tried with a .tlo suffix, then .tl and only if those don't resolve to a file it is tried as-is. The previous order is as-is, .tlo, .tl. Similarly in @(load), but unsuffixed paths are tried as .txr, then .tlo, then .tl. The motivation for this is to avoid probing the filesystem multiple times the optimized case that we care about: loading .tlo files from Lisp. * parser.c (open_txr_file): Rearrange the probing strategy. Also recognize .txr_profile as a suffix, treating it like .tl. This is so that we don't probe for .txr_profile.tlo and .txr_profile.tl before finding the profile. (load_rcfile): Take advantage of the new path-not-found exception. We avoid wastefully checking with path-exists-p to avoid calling open_txr_file. We just let open_txr_file throw an exception if the file doesn't exist, and then distinguish the non-existence case in the handler. * txr.1: Updated @(load) and load documentation.
-rw-r--r--parser.c75
-rw-r--r--txr.1166
2 files changed, 145 insertions, 96 deletions
diff --git a/parser.c b/parser.c
index 89efaca4..f879e50f 100644
--- a/parser.c
+++ b/parser.c
@@ -439,58 +439,67 @@ void open_txr_file(val spec_file, val *txr_lisp_p, val *name, val *stream)
suffix = tl;
else if (match_str(spec_file, lit(".tlo"), negone))
suffix = tlo;
+ else if (match_str(spec_file, lit(".txr_profile"), negone))
+ suffix = tl;
else
suffix = none;
errno = 0;
{
- val spec_file_try = spec_file;
- FILE *in = w_fopen(c_str(spec_file_try), L"r");
+ val spec_file_try = nil;
+ FILE *in = 0;
- if (in != 0) {
- switch (suffix) {
- case tl:
- *txr_lisp_p = t;
- break;
- case tlo:
- *txr_lisp_p = chr('o');
- break;
- case txr:
- *txr_lisp_p = nil;
- break;
- default:
- break;
- }
- }
-
-#ifdef ENOENT
- if (in == 0 && errno != ENOENT)
- goto except;
- errno = 0;
-#endif
-
- if (suffix == none && in == 0 && !*txr_lisp_p) {
+ if (suffix == none && !*txr_lisp_p) {
spec_file_try = scat(lit("."), spec_file, lit("txr"), nao);
in = w_fopen(c_str(spec_file_try), L"r");
#ifdef ENOENT
if (in == 0 && errno != ENOENT)
goto except;
- errno = 0;
#endif
}
-
if (suffix == none) {
if (in == 0) {
spec_file_try = scat(lit("."), spec_file, lit("tlo"), nao);
+ errno = 0;
in = w_fopen(c_str(spec_file_try), L"r");
*txr_lisp_p = chr('o');
+#ifdef ENOENT
+ if (in == 0 && errno != ENOENT)
+ goto except;
+#endif
}
if (in == 0) {
spec_file_try = scat(lit("."), spec_file, lit("tl"), nao);
+ errno = 0;
in = w_fopen(c_str(spec_file_try), L"r");
*txr_lisp_p = t;
+#ifdef ENOENT
+ if (in == 0 && errno != ENOENT)
+ goto except;
+#endif
+ }
+ }
+
+ if (in == 0) {
+ spec_file_try = spec_file;
+ errno = 0;
+ in = w_fopen(c_str(spec_file_try), L"r");
+ if (in != 0) {
+ switch (suffix) {
+ case tl:
+ *txr_lisp_p = t;
+ break;
+ case tlo:
+ *txr_lisp_p = chr('o');
+ break;
+ case txr:
+ *txr_lisp_p = nil;
+ break;
+ default:
+ break;
+ }
}
}
@@ -705,10 +714,6 @@ static void load_rcfile(val name)
val stream = nil;
val catch_syms = cons(error_s, nil);
val path_private_to_me_p = intern(lit("path-private-to-me-p"), user_package);
- val path_exists_p = intern(lit("path-exists-p"), user_package);
-
- if (!funcall1(path_exists_p, name))
- return;
uw_catch_begin (catch_syms, sy, va);
@@ -730,9 +735,11 @@ static void load_rcfile(val name)
uw_catch(sy, va)
{
(void) va;
- format(std_output, lit("** type ~s exception while loading ~a\n"),
- sy, name, nao);
- format(std_output, lit("** details: ~a\n"), car(va), nao);
+ if (stream || sy != path_not_found_s) {
+ format(std_output, lit("** type ~s exception while loading ~a\n"),
+ sy, name, nao);
+ format(std_output, lit("** details: ~a\n"), car(va), nao);
+ }
}
uw_unwind {
diff --git a/txr.1 b/txr.1
index e2529d9b..bec5e75b 100644
--- a/txr.1
+++ b/txr.1
@@ -8500,27 +8500,39 @@ Where
is a Lisp expression that
evaluates to a string giving the path of the file to load.
-If the
+Firstly, the path given by
+.meta expr
+is converted to an effective path, as follows.
+
+If the value of the
.code *load-path*
-has a current value which is not
+variable has a current value which is not
.code nil
and the path is pure relative according to the
.code pure-rel-path-p
-function, then the path is interpreted relative
+function, then the effective path is interpreted taken relative
to the directory portion of the path which is stored in
.codn *load-path* .
If
.code *load-path*
-is nil, or the load path is not pure relative, then it the path is
-taken as-is.
+is nil, or the load path is not pure relative, then the
+path is taken as-is as the effective path.
-If the file named by the path cannot be opened, then the
+Next, an attempt is made to open the file for processing, in
+almost exactly the same manner as by the \*(TL function
+.codn load .
+The difference is that if the effective path is unsuffixed,
+then the
.code .txr
-suffix is added and another
-attempt is made. Thus load expressions need not refer to the suffix.
-In the future, additional suffixes may be searched (compiled versions
-of a file).
+suffix is added to it, and that resulting path is tried first,
+and if it succeeds, then the file is treated as \*(TX Pattern
+Language syntax.
+If that fails, then the suffix
+.code .tlo
+is tried, and so forth, as described for the
+.code load
+function.
Both the
.code load
@@ -8529,44 +8541,57 @@ and
directives bind the
.code *load-path*
variable to the path of the loaded file just before parsing syntax from it,
-and remove the binding when their processing of the file is complete.
-Processing \*(TL code means that each of its forms is read, and evaluated.
-Processing \*(TX code means parsing the entire file in its entirety,
-and then executing its directives against the current input.
-
The
+.code *package*
+variable is also given a new dynamic binding, whose value is the
+same as the existing binding. These bindings are removed when the
+load operation completes, restoring the prior values of these
+variables.
+
+If the file opened for processing is \*(TL source, or
+a compiled \*(TL file, then it is processed in the manner
+described for the
+.code load
+function.
+
+Different requirements apply to the processing of the file under the
.code load
and
.code include
-directives differ as follows.
-The action of
+directives.
+
+The
+.code include
+directive performs the processing of the file at parse time. If the
+file being processed is \*(TX Pattern Language, then it is parsed,
+and then its syntax replaces the
+.code include
+directive, as if it had originally appeared in its place.
+If a \*(TL source or a compiled \*(TL file is processed by
+.code include
+then the
+.code include
+directive is removed from the syntax.
+
+The
.code load
-is not performed immediately but at evaluation time. Evaluation time
+directive performs the processing of the file at evaluation time.
+Evaluation time
occurs after a \*(TX program is read from beginning to end and parsed.
That is to say, when a \*(TX query is parsed, any embedded
.code "@(load ...)"
forms in it are parsed and constitute part of its syntax tree.
-They are executed when that query is executed and its execution
+They are executed when that query is executed, whenever its execution
reaches those
.code load
-directives.
-
-By contrast, the action of
-.code include
-is performed immediately, right after the
-.code "@(include ...)"
-directive syntax is parsed. That is to say, as the \*(TX parser encounters
-this syntax it processes it immediately. The included material is read
-and processed. If it is \*(TX syntax, then it is parsed and incorporated
-into the syntax tree in place of the
-.code include
-directive. The parser then
-continues processing the original file after the
-.code include
-directive. If \*(TL code is processed by the
-.code include
-directive, then its forms are read and evaluated. An empty directive
-is substituted into the syntax tree in this case.
+directives. When the
+.code load
+directive processes \*(TX Pattern Language syntax, it parses
+the file in its entirety and then executes that file's directives
+against the current input position. Repeated executions of the
+same
+.code load
+directive result in repeated processing of the file.
Note: the
.code include
@@ -58399,43 +58424,60 @@ directory.
Once the effective path name is determined,
.code load
-first tries to open that exact path name.
-If this succeeds, then the file will be treated as containing \*(TL,
-unless
-.meta target
-ends with the
+determines whether the name is suffixed. The name is suffixed if it
+ends in any of these four suffixes:
+.codn .tlo ,
+.codn .tl ,
.code .txr
-suffix, in which case the file will be treated as containing
-\*(TX pattern language syntax, or ends with the suffix
-.code .tlo
-in which case it will be treated as a compiled file.
+or
+.codn .txr_profile .
-If loading the original effective path name fails, and that name is unsuffixed,
-then the
+Depending on whether the effective path name is suffixed,
+.code load
+tries to make one or more attempts to open several variations of that name.
+If any attempt fails due to an error other than non-existence,
+such as a permission error, then no further attempts are made; the
+error exception propagates to
+.codn load 's
+caller.
+
+If the effective path name is suffixed, then
+.code load
+tries to open a file by that exact path name. If that attempt
+fails, no other names are tried.
+
+If the effective path name is unsuffixed, then first the suffix
.code .tlo
-suffix is added and a second attempt is made. If that succeeds, the file
-is treated as a compiled \*(TL file.
-Otherwise, the suffix
+is appended to the name, and an attempt is made to open a file
+with this path. If that file is not found, then the suffix
.code .tl
-suffix is added to the original unsuffixed name, and one more attempt is made.
-If that succeeds, the file will be treated as \*(TL.
+is similarly tried. If that file is not found, then the unsuffixed
+name is tried.
-If a file is successfully resolved and opened for \*(TL processing,
-then \*(TL forms are read from it in succession. Each form is evaluated as if
-by the
+If an unsuffixed file is opened, its contents are treated as interpreted Lisp.
+Files ending in
+.code .txr_profile
+are also treated as interpreted Lisp. Files ending in
+.code .tlo
+are treated as compiled Lisp, and those ending in
+.code .txr
+are treated as the \*(TX Pattern Language.
+
+If the file is treated as \*(TL, then Lisp forms are read from it in
+succession. Each form is evaluated as if by the
.code eval
function, before the next form is read.
If a syntax error is encountered, an exception of type
.code eval-error
is thrown.
-If a file is successfully resolved and opened for processing as a
-compiled \*(TL object file, then the compiled images of top-level forms
-are read from it, converted into compiled objects, and executed.
+If a file is treated as a compiled \*(TL object file, then the compiled images
+of top-level forms are read from it, converted into compiled objects, and
+executed.
-If a file is successfully resolved and opened for \*(TX processing,
-then its contents are parsed in their entirety as a \*(TX
-query. If the parse is successful, the query is executed.
+If the file treated as \*(TX Pattern Language code,
+then its contents are parsed in their entirety.
+If the parse is successful, the query is executed.
Previous \*(TX pattern variable and function bindings are in
effect. If the query binds new variables and functions,
these emerge from the