https://github.com/phoe/in-nomine
Utility for creating, accessing, and managing custom namespaces in Common Lisp.
https://github.com/phoe/in-nomine
Last synced: 4 months ago
JSON representation
Utility for creating, accessing, and managing custom namespaces in Common Lisp.
- Host: GitHub
- URL: https://github.com/phoe/in-nomine
- Owner: phoe
- Created: 2022-01-29T10:21:22.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-11-26T08:08:42.000Z (over 2 years ago)
- Last Synced: 2025-02-24T04:27:04.404Z (over 1 year ago)
- Language: Common Lisp
- Size: 144 KB
- Stars: 15
- Watchers: 4
- Forks: 3
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## In Nomine
> The beginning of wisdom is to call things by their proper name.
>
> -- Confucius
This is a utility for creating, accessing, and managing custom namespaces in Common Lisp. Originally started as a fork of [`LISP-NAMESPACE`](https://github.com/guicho271828/lisp-namespace), it became its own piece of software that is *somewhat* backwards compatible with it.
## Syntax differences from `LISP-NAMESPACE`
* Removed macros `NAMESPACE-LET` and `NSLET`,
* Removed the `DEFINE-NAMESPACE` option to automatically generate `NAMESPACE-LET`-based binding macros,
* Added boundp and makunbound functions for namespace names,
* Moved hash tables for bindings and documentation from being implicitly created as variables to slots of the namespaces objects themselves (unless requested otherwise),
* Added long form of `DEFINE-NAMESPACE` to customize behavior of generated namespaces,
* Exported namespace objects and their readers.
## Manual
A namespace is a second-class concept in Common Lisp and refers to concept that allows to associate names of some sort with objects of some sort.
Common Lisp has a lot of namespaces whose keys can come in various shapes:
* interned symbols (package-and-string tuples),
* variables and symbol macros (symbols),
* functions and macros (symbols),
* compiler macros (symbols),
* `SETF` expansions (Lisp forms),
* classes, conditions, and types (symbols),
* slot names (symbols),
* method combinations (symbols),
* block names (symbols),
* tagbody tags (symbols and integers),
* declarations (symbols),
* lambda list keywords (symbols),
* catch tags (any Lisp objects),
* restarts (symbols),
* packages (strings),
* modules (strings),
* logical pathname hosts (strings),
* reader macros (characters),
* character codes (characters),
* character names (strings),
* characters *(only true on some implementations)* (integers),
* ...
* ASDF systems (lowercase strings),
* ... (people can make new ones!)
This system is a utility to bring a first-class implementation of the concept of namespaces along with utilities to customize and manage them.
The heart of the facility is the `DEFINE-NAMESPACE` macro, which comes in two forms: short (syntax-compatible with [`LISP-NAMESPACE:DEFINE-NAMESPACE`](https://github.com/guicho271828/lisp-namespace) and with mostly compatible effects) and long form (allowing for greater behavior customization).
`DEFINE-NAMESPACE`, by default, generates functions for accessing the namespace, a condition signaled whenever an access to an unbound name is attempted, a type which denotes the values permissible in a namespace, and documentation types.
By default, names are symbols and compared via `EQ`. This behavior is consistent with the way Common Lisp names variables and classes.
```lisp
IN-NOMINE> (define-namespace thing)
#
IN-NOMINE> (setf (symbol-thing 'foo) 42
(symbol-thing 'bar) :keyword
(symbol-thing 'baz) *readtable*)
#
IN-NOMINE> (mapcar #'symbol-thing '(foo bar baz))
(42 :KEYWORD #)
```
It is possible to customize this behavior, though, and get e.g. a namespace in which names are non-negative numbers.
```lisp
IN-NOMINE> (define-namespace player
;; Use numbers as hash table keys
:name-type unsigned-byte
;; Numbers are EQL-comparable
:hash-table-test eql
:accessor player-no)
#
IN-NOMINE> (setf (player-no 8) :jerry
(player-no 0) :thomas
(player-no 2) :michael)
:MICHAEL
IN-NOMINE> (player-no 8)
:JERRY
IN-NOMINE> (player-no 1)
;; Error: Name 1 is unbound in namespace PLAYER.
;; [Condition of type UNBOUND-PLAYER]
```
It is possible to utilize different name types along with all four standard hash table keys and produce namespaces with different possible name values. Examples:
* `EQ` for symbols,
* `EQL` for numbers and characters,
* `EQUAL` for strings or lists,
* `EQUALP` for strings without case sensitivity.
It is possible to define a definer macro for the namespace.
```lisp
IN-NOMINE> (define-namespace game
:definer-name defgame
:definer cons)
#
IN-NOMINE> (defgame some-game 8 3)
(8 . 3)
IN-NOMINE> (symbol-game 'some-game)
(8 . 3)
```
In Nomine by default provides documentation types with the same names as namespace names.
```lisp
IN-NOMINE> (setf (documentation 8 'player) "The best player ever.")
"The best player ever."
IN-NOMINE> (documentation 8 'player)
"The best player ever."
```
In addition, In Nomine hooks into implementation-defined `CL:DESCRIBE` in order to provide information about namespace bindings.
```lisp
IN-NOMINE> (describe 'foo)
IN-NOMINE::FOO
[symbol]
Symbol FOO is bound in namespace THING:
Value: 42
(undocumented)
; No value
IN-NOMINE> (describe 8)
8
[fixnum]
8 is bound in namespace PLAYER:
Value: :JERRY
Documentation:
The best player ever.
; No value
```
## API
### Packages
#### Package `IN-NOMINE`
Loaded via `(asdf:load-system :in-nomine)`.
Utilities for defining additional namespaces in Common Lisp.
Common Lisp is a Lisp-N, which means that it has a different namespaces for variables, functions, types, and so on. Users can also define their own namespaces, and In Nomine is a toolkit for making that process easier.
### Namespace definition and management
#### Macro `DEFINE-NAMESPACE`
Defines a new namespace object in the global namespace namespace along with
a series of functions, types, conditions, and type proclamations for accessing
this namespace.
Two forms of this macro are provided:
* short form:
* `(DEFINE-NAMESPACE NAME &OPTIONAL VALUE-TYPE BINDING DOCUMENTATION)`
* `NAME` - a symbol naming the namespace,
* `VALUE-TYPE` - a type specifier for values bound in this namespace,
* `BINDING` - deprecated, only present for syntax compatibility with [`LISP-NAMESPACE`](https://github.com/guicho271828/lisp-namespace); must be `NIL` when provided,
* `DOCUMENTATION` - documentation string for the namespace object.
* For name `FOO`, the following are generated:
* Accessor functions `SYMBOL-FOO` and `(SETF SYMBOL-FOO)`,
* Makunbound function `FOO-MAKUNBOUND`,
* Boundp function `FOO-BOUNDP`,
* Type proclamations for the four functions above,
* Condition type `UNBOUND-FOO`,
* Type `FOO-TYPE` denoting the specified `VALUE-TYPE`,
* Documentation methods with documentation type specialized on `(EQL 'FOO)`.
* long form:
* `(DEFINE-NAMESPACE NAME &KEY NAME-TYPE VALUE-TYPE ACCESSOR CONDITION-NAME TYPE-NAME MAKUNBOUND-SYMBOL BOUNDP-SYMBOL DOCUMENTATION-TYPE ERROR-WHEN-NOT-FOUND-P ERRORP-ARG-IN-ACCESSOR-P DEFAULT-ARG-IN-ACCESSOR-P HASH-TABLE-TEST BINDING-TABLE-VAR DOCUMENTATION-TABLE-VAR DOCUMENTATION DEFINER-NAME DEFINER)`
* `NAME` - a symbol naming the namespace,
* `NAME-TYPE` - a type specifiers for keys bound in this namespace,
* `VALUE-TYPE` - a type specifier for values bound in this namespace,
* `ACCESSOR` - a symbol naming the accessor functions, or `NIL` if no such accessor should be defined,
* `CONDITION-NAME` - a symbol naming the condition type signaled when an attempt is made to access an unbound name, or `NIL` if no such accessor should be defined,
* `TYPE-NAME` - a symbol naming the type for the namespace values, or `NIL` if no such type should be defined,
* `MAKUNBOUND-SYMBOL` - symbol naming the namespace makunbound function, or `NIL` if no such function should be defined,
* `BOUNDP-SYMBOL` - a symbol naming the namespace boundp function, or `NIL` if no such function should be defined,
* `DOCUMENTATION-TYPE` - a symbol naming the documentation type for the namespace values, or `NIL` if no such documentation should be defined,
* `ERROR-WHEN-NOT-FOUND-P` - a boolean stating whether a reader function should signal an error if it attempts to access an unbound name,
* `ERRORP-ARG-IN-ACCESSOR-P` - a boolean stating whether accessor functions should have an optional `ERRORP` argument for stating whether an unbound condition should be signaled when an attempt is made to access an unbound name,
* `DEFAULT-ARG-IN-ACCESSOR-P` - a boolean stating whether accessor functions should have an optional `DEFAULT` argument for automatic setting of unbound values,
* `HASH-TABLE-TEST` - a symbol naming the hash table test of the binding and documentation hash tables of the namespace,
* `BINDING-TABLE-VAR` - a symbol naming the variable whose value shall be the binding table of the namespace, or `NIL` if no such variable should be defined,
* `DOCUMENTATION-TABLE-VAR` - a symbol naming the variable whose value shall be the documentation table of the namespace, or `NIL` if no such variable should be defined,
* `DOCUMENTATION` - documentation string for the namespace object.
* `DEFINER-NAME` - name of the definer for a definition in the namespace; defaults to `DEFINE-[NAME]` if a definer is to be defined
* `DEFINER` - can have one of several forms, defines a macro with name `[DEFINER-NAME]` whose lambda list always starts with a gensymed argument `BINDING-NAME` for the name of the defined binding
* `NIL` - if no `DEFINER-NAME` is given, don't define a definer, otherwise define a standard definer with argument list `BINDING-NAME OBJECT` that binds `BINDING-NAME` to the result of evaluating `OBJECT`
* `T` - like `NIL`, but also defines a definer if `DEFINER-NAME` has not been supplied
* `[FUNCTION]`, `'[FUNCTION]`, `#'[FUNCTION]` - define a definer with argument-list `BINDING-NAME [LAMBDA-LIST-OF-FUNCTION]`, which binds `BINDING-NAME` to the result of calling `[FUNCTION]` on the rest of the arguments
* `(LAMBDA (ARGS) BODY*)` - same as with named functions, but with the given anonymous function
* `(LAMBDA-LIST BODY*)` - the lambda list can be a generalized lambda list; body should evaluate to the code executed to produce the object to bind `BINDING-NAME` to
The consequences are undefined if a namespace is redefined in an incompatible
way with the previous one.
#### Function `SYMBOL-NAMESPACE`
Returns a namespace object with the given global name. Signals `UNBOUND-NAMESPACE` unless `ERRORP` is set.
#### Function `CLEAR-NAMESPACE`
Removes all bindings in the namespace with the given name.
#### Function `NAMESPACE-MAKUNBOUND`
Makes the name globally unbound as a namespace regardless of whether the name was previously bound.
#### Function `NAMESPACE-BOUNDP`
Returns true if a namespace object with the provided name is globally bound, false otherwise.
#### Condition Type `UNBOUND-NAMESPACE`
A subtype of `CELL-ERROR` signaled when there is an attempt to access a namespace object that does not exist.
### Namespace class and accessors
#### Class `NAMESPACE`
A class of namespace objects which represent a Common Lisp namespace.
#### Function `NAMESPACE-NAME`
Returns the symbol naming a namespace.
#### Function `NAMESPACE-NAME-TYPE`
Returns the type of names that are possible to bind in a namespace.
#### Function `NAMESPACE-VALUE-TYPE`
Returns the type of values that are possible to bind in a namespace.
#### Function `NAMESPACE-ACCESSOR`
Returns the symbol naming the namespace accessor, or `NIL` if no such accessor is defined.
#### Function `NAMESPACE-CONDITION-NAME`
Returns the symbol naming the condition type signaled when an attempt is made to access an unbound name, or `NIL` if no such condition type is defined
#### Function `NAMESPACE-TYPE-NAME`
Returns the symbol naming the type for the namespace values, or `NIL` if no such type is defined.
#### Function `NAMESPACE-MAKUNBOUND-SYMBOL`
Returns the symbol naming the namespace makunbound function, or `NIL` if no such function exists.
#### Function `NAMESPACE-BOUNDP-SYMBOL`
Returns the symbol naming the namespace boundp function, or `NIL` if no such function exists.
#### Function `NAMESPACE-DOCUMENTATION-TYPE`
Returns the symbol naming the documentation type for the namespace values, or `NIL` if no such documentation type exists.
#### Function `NAMESPACE-ERROR-WHEN-NOT-FOUND-P`
Returns a boolean stating whether a reader function should signal an error if it attempts to access an unbound name.
#### Function `NAMESPACE-ERRORP-ARG-IN-ACCESSOR-P`
Returns a boolean stating whether accessor functions should have an optional `ERRORP` argument for stating whether an unbound condition should be signaled when an attempt is made to access an unbound name.
#### Function `NAMESPACE-DEFAULT-ARG-IN-ACCESSOR-P`
Returns a boolean stating whether accessor functions should have an optional `DEFAULT` argument for automatic setting of unbound values.
#### Function `NAMESPACE-HASH-TABLE-TEST`
Returns the symbol naming the hash table test of the binding and documentation hash tables of the namespace.
#### Function `NAMESPACE-BINDING-TABLE`
Returns the binding hash table, or `NIL` if `BINDING-TABLE-VAR` is defined or no binding mechanism is defined.
#### Function `NAMESPACE-DOCUMENTATION-TABLE`
Returns the documentation hash table, or `NIL` if no documentation type is defined.
#### Function `NAMESPACE-BINDING-TABLE-VAR`
Returns the symbol naming the variable whose value is the binding table of the namespace, or `NIL` if no such variable is defined. Changing the value or dynamically binding this variable will affect the global environment of the namespace.
#### Function `NAMESPACE-DOCUMENTATION-TABLE-VAR`
Returns the symbol naming the variable whose value is the documentation table of the namespace, or `NIL` if no such variable is defined.
### Namespaces
#### Namespace `NAMESPACE`
A namespace for managing namespaces.
## License
* Copyright (c) 2015 [Masataro Asai](guicho2.71828@gmail.com)
* Copyright (c) 2022 [Michał "phoe" Herda](phoe@disroot.org)
Licensed under the LLGPL License.
> A man that should call everything by its right name, would hardly pass the streets without being knocked down as a common enemy.
>
> -- Lord Halifax