summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-04-03 20:36:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-04-03 20:36:23 -0700
commit7bc150f6d87b836b7690f8d73ee815ea8c718b13 (patch)
treecfd00d9675a70a46b512616483c1741d68b8fb47
parent3ce8999b2cc9c2aa04805141af9cb449d92fa89e (diff)
downloadtxr-7bc150f6d87b836b7690f8d73ee815ea8c718b13.tar.gz
txr-7bc150f6d87b836b7690f8d73ee815ea8c718b13.tar.bz2
txr-7bc150f6d87b836b7690f8d73ee815ea8c718b13.zip
packages: fix package prefix read/print issue.
Suppose that we have two symbols of the same name, in two packages: foo:sym and bar:sym. Suppose that the bar package has foo in its package fallback list, and suppose bar is the current package. Then bar:sym prints without a package prefix, as just sym. However, this is potentially ambiguous. Suppose that bar:sym is written to a file as just sym. Then later the file is read into a fresh image in a situation in which bar:sym has not yet been interned, but foo:sym already exists. In this situation, sym will just resolve to foo:sym. The printer must detect this ambiguous situation. If a symbol is present in a package, but a same-named symbol is in the fallback list; or if a symbol is visible in the fallback list, but a same-named symbol is present in the package, then a package prefix should be printed. * lib.c (symbol_needs_prefix): New function. (unquote_star_check, obj_print_impl): Use symbol_needs_prefix rather than symbol_visible. * lib.h (symbol_needs_prefix): Declared.
-rw-r--r--lib.c46
-rw-r--r--lib.h1
2 files changed, 45 insertions, 2 deletions
diff --git a/lib.c b/lib.c
index b3169d2c..f089ee90 100644
--- a/lib.c
+++ b/lib.c
@@ -5430,6 +5430,48 @@ val symbol_visible(val package, val sym)
return nil;
}
+/* symbol_needs_prefix assumes the perspective that package
+ * is the current package!
+ */
+val symbol_needs_prefix(val package, val sym)
+{
+ val name = symbol_name(sym);
+ type_check (package, PKG);
+
+ {
+ int homed_here = (sym->s.package == package);
+ val home_cell = gethash_e(package->pk.symhash, name);
+ int present_here = (eq(cdr(home_cell), sym) != nil);
+ val fallback = get_hash_userdata(package->pk.symhash);
+ val fb_cell = nil;
+ int in_fallback = 0;
+
+ for (; fallback; fallback = cdr(fallback)) {
+ val fb_pkg = car(fallback);
+ val cell = gethash_e(fb_pkg->pk.symhash, name);
+
+ if (cell) {
+ fb_cell = cell;
+ if (eq(cdr(cell), sym) != nil) {
+ in_fallback = 1;
+ break;
+ }
+ }
+ }
+
+ if (!homed_here && !present_here && !in_fallback)
+ return t;
+
+ if ((homed_here || present_here) && fb_cell)
+ return t;
+
+ if (in_fallback && home_cell)
+ return t;
+ }
+
+ return nil;
+}
+
val find_symbol(val str, val package_in)
{
val self = lit("find-symbol");
@@ -10953,7 +10995,7 @@ static int unquote_star_check(val obj, val pretty)
return 0;
if (car(obj->s.name) != chr('*'))
return 0;
- return pretty || symbol_visible(cur_package, obj);
+ return pretty || !symbol_needs_prefix(cur_package, obj);
}
val obj_print_impl(val obj, val out, val pretty, struct strm_ctx *ctx)
@@ -11215,7 +11257,7 @@ dot:
put_string(lit("#:"), out);
} else if (obj->s.package == keyword_package) {
put_char(chr(':'), out);
- } else if (!symbol_visible(cur_package, obj)) {
+ } else if (symbol_needs_prefix(cur_package, obj)) {
put_string(obj->s.package->pk.name, out);
put_char(chr(':'), out);
}
diff --git a/lib.h b/lib.h
index f39f075a..6fe29fe2 100644
--- a/lib.h
+++ b/lib.h
@@ -843,6 +843,7 @@ val unuse_sym(val symbol, val package);
val use_package(val use_list, val package);
val unuse_package(val unuse_list, val package);
val symbol_visible(val package, val sym);
+val symbol_needs_prefix(val package, val sym);
val find_symbol(val str, val package);
val intern(val str, val package);
val unintern(val sym, val package);