diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2018-04-03 20:36:23 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2018-04-03 20:36:23 -0700 |
commit | 7bc150f6d87b836b7690f8d73ee815ea8c718b13 (patch) | |
tree | cfd00d9675a70a46b512616483c1741d68b8fb47 | |
parent | 3ce8999b2cc9c2aa04805141af9cb449d92fa89e (diff) | |
download | txr-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.c | 46 | ||||
-rw-r--r-- | lib.h | 1 |
2 files changed, 45 insertions, 2 deletions
@@ -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); } @@ -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); |