summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c17
-rw-r--r--lib.h3
-rw-r--r--stdlib/doc-syms.tl3
-rw-r--r--stdlib/package.tl4
-rw-r--r--tests/012/use-as.tl31
-rw-r--r--txr.1176
7 files changed, 203 insertions, 32 deletions
diff --git a/eval.c b/eval.c
index 399e3aa8..094ecb71 100644
--- a/eval.c
+++ b/eval.c
@@ -7548,6 +7548,7 @@ void eval_init(void)
reg_fun(intern(lit("package-local-symbols"), user_package), func_n1o(package_local_symbols, 0));
reg_fun(intern(lit("package-foreign-symbols"), user_package), func_n1o(package_foreign_symbols, 0));
reg_fun(intern(lit("use-sym"), user_package), func_n2o(use_sym, 1));
+ reg_fun(intern(lit("use-sym-as"), user_package), func_n3o(use_sym_as, 2));
reg_fun(intern(lit("unuse-sym"), user_package), func_n2o(unuse_sym, 1));
reg_fun(intern(lit("use-package"), user_package), func_n2o(use_package, 1));
reg_fun(intern(lit("unuse-package"), user_package), func_n2o(unuse_package, 1));
diff --git a/lib.c b/lib.c
index 1ce03dc2..d7a7ce66 100644
--- a/lib.c
+++ b/lib.c
@@ -7314,13 +7314,19 @@ static void prot_sym_check(val func, val symname, val package)
}
}
-val use_sym(val symbol, val package_in)
+val use_sym_as(val symbol, val name, val package_in)
{
- val self = lit("use-sym");
+ val self = lit("use-sym-as");
val package = get_package(self, package_in, t);
+ if (symbolp(name))
+ name = symbol_name(name);
+ else if (!stringp(name))
+ uw_throwf(error_s,
+ lit("~a: ~s: name must be specified as string or symbol"),
+ self, name, nao);
+
if (symbol_package(symbol) != package) {
- val name = symbol_name(symbol);
val found = gethash_e(self, package->pk.symhash, name);
val existing = cdr(found);
@@ -7338,6 +7344,11 @@ val use_sym(val symbol, val package_in)
return symbol;
}
+val use_sym(val sym, val package_in)
+{
+ return use_sym_as(sym, symbol_name(sym), package_in);
+}
+
val unuse_sym(val symbol, val package_in)
{
val self = lit("unuse-sym");
diff --git a/lib.h b/lib.h
index 646af602..c7e4165d 100644
--- a/lib.h
+++ b/lib.h
@@ -1135,7 +1135,8 @@ val package_alist(void);
val package_name(val package);
val package_symbols(val package);
val package_local_symbols(val package);
-val use_sym(val use_list, val package);
+val use_sym_as(val symbol, val name, val package_in);
+val use_sym(val sym, val package);
val unuse_sym(val symbol, val package);
val use_package(val use_list, val package);
val unuse_package(val unuse_list, val package);
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index be86e9d7..d1f31708 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -2210,7 +2210,8 @@
("url-encode" "N-0388DB26")
("use" "N-004834CC")
("use-package" "N-024BF63F")
- ("use-sym" "N-01747674")
+ ("use-sym" "N-028B0A16")
+ ("use-sym-as" "N-028B0A16")
("user-package" "N-0383342A")
("ushort" "N-0235F4E4")
("usl" "N-00BF39DD")
diff --git a/stdlib/package.tl b/stdlib/package.tl
index baede5b7..d420081f 100644
--- a/stdlib/package.tl
+++ b/stdlib/package.tl
@@ -61,6 +61,10 @@
(:use-syms
^((each ((s ',rest))
(use-sym s ,pkg))))
+ (:use-syms-as
+ ^((doloop ((r ',rest (cddr r)))
+ (r)
+ (use-sym-as (car r) (cadr r) ,pkg))))
(:local
^((each ((n ',(mapcar (op sys:name-str 'symbol)
rest)))
diff --git a/tests/012/use-as.tl b/tests/012/use-as.tl
new file mode 100644
index 00000000..681a968d
--- /dev/null
+++ b/tests/012/use-as.tl
@@ -0,0 +1,31 @@
+(load "../common")
+
+(defpackage lottery
+ (:local draw)
+ (:fallback usr))
+
+(defpackage graphics
+ (:local draw)
+ (:fallback usr))
+
+(defpackage gui-lottery
+ (:fallback lottery graphics usr pub)
+ (:use-syms-as lottery:draw ldraw
+ graphics:draw gdraw))
+
+(in-package gui-lottery)
+
+(mtest
+ (package-name (symbol-package 'ldraw)) "lottery"
+ (package-name (symbol-package 'gdraw)) "graphics"
+ (symbol-name 'ldraw) "draw"
+ (symbol-name 'gdraw) "draw")
+
+(mtest
+ (tostring 'ldraw) "draw"
+ (tostring 'gdraw) "graphics:draw")
+
+(mtest
+ (use-sym-as 3 '#:foo) :error
+ (use-sym-as 'ldraw 3) :error
+ (use-sym-as 'x 'x) x)
diff --git a/txr.1 b/txr.1
index 5a14573f..9a7f8886 100644
--- a/txr.1
+++ b/txr.1
@@ -66129,9 +66129,9 @@ When a package is deleted with
.codn delete-package ,
its symbols are uninterned from all other packages.
-An existing symbol can be brought into a package via the
+An symbol existing in one package can be brought into another package via the
.code use-sym
-function, causing it to be interned in that package. A symbol which thus exists
+function, causing it to be interned in the target package. A symbol which thus exists
inside a package which is not its home package is called a
.IR "foreign symbol" ,
relative to that package.
@@ -66143,6 +66143,13 @@ which refers to a symbol, relative to a package, which is interned in that
package and that package is also its home. Every symbol interned in
a package is either foreign or local.
+An existing symbol can also be brought into a package under a different
+name using the
+.code use-sym-as
+function, causing it to be interned under an alternative name.
+This has the effect of creating a local alias for a foreign symbol,
+and is intended as a renaming mechanism for resolving name clashes.
+
If a foreign symbol is introduced into a package, and has the same name
as an existing local symbol, the local symbol continues to exist, but
is hidden: it is not accessible via a name lookup on that package.
@@ -66252,6 +66259,73 @@ as the current package in the
variable. It then allows unqualified symbol references to refer across
the fallback list.
+The \*(TL package system does not feature package nicknames,
+which have been found to be a source of clashes in large Common Lisp
+software collections, leading to the development of a feature
+called package local nicknames that is not part of ANSI CL, but
+supported by a number of implementations. In \*(TL,
+packages have only one name, accessible via
+.codn package-name .
+\*(TL packages are held in an association list called
+.codn *package-alist* ,
+which is public, which associates string names with packages.
+The function
+.code find-package
+which is used by the parser when looking up the package prefix
+of a qualified symbol, only uses the names which appears as keys
+in this association list. Usually those names are the same as
+the names of the package objects. However, it's possible to manipulate
+this association list to create alias names for packages.
+Thus, it is possible for
+.code "(find-package \(dqfoo\(dq)"
+to return
+.code "#<package: bar>"
+if the name
+.str foo
+is associated, in
+.code *package-alist*
+with a package object named
+.strn bar .
+
+The \*(TL package system doesn't feature package local nicknames.
+There are three reasons for this. One is that it doesn't have global package
+nicknames. The second is that the mechanism would be cumbersome,
+and add delay to the resolution of qualified symbols, requiring
+nicknames in the
+.code *package*
+to be searched for a package name, in addition to the dynamic
+.codn *package-alist* .
+The third reason is that package local nicknames do not actually solve the
+problem of clashing symbols, when an application uses multiple packages
+that each define a symbol by the same name. Package nicknames only
+shorten the qualified names required to refer to the symbols,
+Instead, \*(TL allows a foreign symbol to be interned in a
+package under a name which is different from its
+.codn symbol-name .
+Thus, rather than creating aliases for package names,
+\*(TL packages can locally rename the actual clashing symbols,
+which can then be referenced by unqualified names.
+
+By manipulating
+.codn *package-alist* ,
+a \*(TL source file can nevertheless achieve the creation of a
+de facto package nickname, which is local to a loaded file,
+by following the following example:
+
+.verb
+ ;; make sure that when this file finishes loading,
+ ;; or the loading is interrupted by an exception,
+ ;; the "u" package alias is deleted from *package-alist*
+ (push-after-load
+ (set *package-alist* [remqual "u" *package-alist* car]))
+
+ ;; push an alias named u for the usr package.
+ (push (cons "u" (find-package "usr")) *package-alist*)
+
+ ;; u: can now be used, until the end of this file
+ (u:prinl (u:list 1 2 3))
+.brev
+
.NP* Package Examples
The following example illustrates a simple scenario of a module
whose identifies are in a package, and which also has private identifiers
@@ -67153,55 +67227,86 @@ special symbols
and
.codn nil .
-.coNP Function @ use-sym
+.coNP Functions @ use-sym and @ use-sym-as
.synb
.mets (use-sym < symbol <> [ package ])
+.mets (use-sym-as < symbol < name <> [ package ])
.syne
.desc
The
.code use-sym
function brings an existing
-.code symbol
+.meta symbol
into
.metn package .
-In all cases, the function returns
+The
+.code use-sym-as
+is similar, but allows an alternative
+.meta name
+to be specified. The
+.meta symbol
+will be interned under that name, rather than under its symbol name.
+
+In all cases, both function return
.codn symbol .
-If
+The following equivalence holds:
+
+.verb
+ (use-sym s p) <--> (use-sym-as s (symbol-name s) p)
+.brev
+
+Thus, in the following descriptions, when the remarks are interpreted
+as applying to
+.codn use-sym ,
+the
+.meta name
+argument is understood as referring to the
+.code symbol-name
+of the
.meta symbol
-is already interned in
-.metn package ,
+argument.
+
+If
+.meta package
+is the home package of
+.metn symbol ,
then the function has no effect.
Otherwise
.meta symbol
is interned in
-.metn package .
+.meta package
+under
+.metn name .
-If a symbol having the same name as
-.meta symbol
-already exists in
-.metn package ,
-then it is replaced.
+If a symbol is already interned in
+.meta package
+under
+.metn name ,
+then that symbol is is replaced.
If that replaced symbol is a local symbol of
.metn package ,
-then the replaced symbol turns into a hidden symbol associated
+meaning that
+.meta package
+is its home package,
+then that replaced symbol turns into a hidden symbol associated
with the package. It is placed into a special hidden symbol store
associated with
.meta package
and is stripped of its home package, becoming quasi-interned or uninterned.
-An odd case is possible whereby
-.meta symbol
-is already a hidden symbol of
-.metn package .
-In this case, the hidden symbol replaces some foreign symbol and
-is interned in
-.metn package .
-Thus it simultaneously exists as both an interned
-foreign symbol and as a hidden symbol of
-.metn package .
+Note:
+.code use-sym
+and
+.code use-sym-as
+are the basis for the
+.code defpackage
+clauses
+.code :use-syms
+and
+.codn :use-syms-as .
.coNP Function @ unuse-sym
.synb
@@ -67353,8 +67458,25 @@ The list of package names is processed as if by a call to
.meIP (:use-syms << symbol *)
The
.code :use-syms
-clause specifies individual symbols to be interned in the present package.
-The arguments are symbols.
+clause specifies individual symbols to be brought into the present
+package, as if by the
+.code use-sym
+function. The arguments are symbols.
+.meIP (:use-syms-as >> { symbol << name }*)
+The
+.code :use-syms-as
+clause specifies individual symbols to be brought into the present
+package, as if by the
+.code use-sym-as
+function. The arguments constitute a property list consisting of interleaved
+symbols and names. Each
+.meta symbol
+argument is a symbol, and each
+.meta name
+is either a symbol or a string. If it is a symbol, then its name
+is retrieved via
+.code symbol-name
+and used in its place.
.meIP (:use-from < package-name << symbol-name *)
The
.code :use-from