An open API service indexing awesome lists of open source software.

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.

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