diff options
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | lib.c | 17 | ||||
-rw-r--r-- | lib.h | 3 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 3 | ||||
-rw-r--r-- | stdlib/package.tl | 4 | ||||
-rw-r--r-- | tests/012/use-as.tl | 31 | ||||
-rw-r--r-- | txr.1 | 176 |
7 files changed, 203 insertions, 32 deletions
@@ -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)); @@ -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"); @@ -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) @@ -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 |