shithub: purgatorio

ref: ccd7f9f1597e56d121e1d05cf6af86f688ef2c48
dir: /man/1/sh-alphabet/

View raw version
.TH SH-ALPHABET 1
.SH NAME
alphabet, typeset, declare, import, type, define, autodeclare,
autoconvert, -, rewrite, modules, types, usage, info, clear \- typed shell interface
.SH SYNOPSIS
.B load alphabet

.B type
.IR qname ...
.br
.B declare
.I name
[
.I usage
]
.br
.B undeclare
.IR name ...
.br
.B define
.I name
.I expr
.br
.B import
.IR qname ...
.br
.B typeset
.I qname
.br
.B autoconvert
.I srctype dsttype expr
.br
.B autodeclare
.BR "" 0 | 1
.br
.B -
.BI { expression }
.br
.B ${rewrite {\fIexpression\fP}
[
.I dsttype
]
.B }
.br
.B ${modules}
.br
.B ${types
.I typeset
.B }
.br
.B ${usage
.I qname
.B }
.br
.B info
.br
.B clear
.SH DESCRIPTION
.I Alphabet
is a loadable
.IR sh (1)
module providing an interface to a simple, experimental, typed shell.
It initially provides a small set of basic types, which can be added
to by loading new
.IR typeset s.
Types are atomic;
.I alphabet
provides no support for higher-order
types.
The
.IR "root typeset" ,
named
.BR / ,
consists of the following kinds of value:
.TP 10
.B string
A simple string literal, represented by itself,
or quoted according to the usual shell quoting rules.
.TP
.B cmd
A shell command or uninterpreted
.I alphabet
expression, represented by the syntax \f5"{\fIblock\f5}\fR.
.TP
.B fd
A file open for reading.
.TP
.B wfd
A file open for reading and writing.
.TP
.B status
The status of a completed command.
.PP
Each typeset implements a set of
types, and has an associated set of
.IR module s.
Initially, types may only be referred to by their
.IR "qualified name" s,
consisting of the name of the type prefixed with
the name of its typeset; for instance
.B /string
for the string type,
or
.B /grid/data
for a type named
.B data
in the typeset
.BR /grid .
An
.I "unqualified name"
is the qualified name without the typeset prefix;
for instance
.B string
or
.BR data .
.PP
To make a type available as its unqualified name,
use the
.B type
command, which imports the type named
by the qualified name
.I qname
from its parent typeset.
This is a no-op if the type has previously been imported
from the same typeset; an error is raised if the type
has previously been imported from a different typeset.
.PP
.B Declare
declares the module
.IR name
with type
.IR usage .
If
.I name
is a qualified name, the module must exist in the
specified typeset and be compatible with the specified usage.
If
.I usage
is not given, the module itself will be loaded and queried
to find it out.
If
.I name
is not qualified, the declaration is
.IR virtual :
the module cannot actually be used, but is available
for typechecking and expression rewriting.
.B Declare
is a no-op if the module has already been declared
with a compatible usage, otherwise an error is raised.
The syntax of
.I usage
is similar to the usage messages printed by normal
shell commands, and defines the argument types expected
by a module. For example:
.IP
.EX
declare /foo/bar '[-a] [-x string] fd string [string...] -> fd'
.EE
.PP
The above declares the module
.B bar
from typeset
.BR /foo ,
which takes
two possible options (one of which requires a single
associated argument of type
.BR string ),
two mandatory arguments,
of type
.B fd
and
.B string
respectively,
and any number of additional arguments of
type
.BR string .
The module returns a value of type
.BR fd .
.PP
When first loaded,
.I alphabet
is lax about declaration requirements:
if a module is referred to by its qualified name,
and is not currently declared, the module will automatically
be declared and used as appropriate (as long as the module
actually exists).
Use
.B autodeclare
to change this behaviour.
.B "Autodeclare 0"
turns off all automatic declaration: all modules used in an
expression must have previously been declared;
.B "autodeclare 1"
reverts to the original behaviour.
.PP
Once a module is declared, it may be referred to
by its qualified name.
.B Import
makes the module available under its unqualified name.
It is an error if a module of the same name has
already been imported from a different typeset.
For instance:
.IP
.EX
declare /read 'string -> fd'
import /read
.EE
.PP
This would declare a module named
.B read
from the root typeset (checking that it
accepts a single string argument and returns a file),
and make it available under the name
.BR read .
.PP
.B Undeclare
removes the previously declared
.IR name .
Note that an imported module has two names:
its qualified name and its unqualified name.
.PP
.B Typeset
loads the new typeset
.IR qname .
Typesets are hierarchical in the same
way that types and modules are: a typeset adds some
types to its parent typeset, and has an associated set of
modules that provide transformations between those types
and between those of its parent.
.PP
.B Autoconvert
specifies an automatic conversion between
.I srctype
and
.IR dsttype ,
i.e. whereever a module expects an argument
of type
.IR dsttype ,
and the argument is actually of type
.IR srctype ,
the module block (see below for definition)
.I expr
(which must be compatible with type
.IB srctype -> dsttype\fR),
will be invoked to convert between the two.
Several conversions will be applied
atop one another if necessary.
It is an error if adding the auto-conversion
creates an ambiguous conversion path
between two types.
As a convenience,
.I expr
may simply be the name of a module,
in which case the expression will be rewritten as
its identity module block: \f5{(\fIsrctype\fP); \fIexpr\fP}\fR.
.PP
The
.B -
command evaluates the
.I alphabet
.IR expression ,
of the form:
.IP
.EX
{\fIcommand arg\fR...\f5}
.EE
.PP
Usually,
.I command
is the name of a previously declared module,
which must also have been imported if it is not a qualified name.
The arguments must conform to those expected by
the module. Each argument is either a literal string or shell-command,
as described earlier, or a subexpression of the same form as above.
All subexpressions are evaluated fully before
.I command
is invoked.
The result of the outermost expression must be convertible to the type
.BR /status ;
the shell status of the
.B -
command will reflect this when the command has completed.
.PP
As a convenience,
.I alphabet
provides a pipe-like syntax. It will rewrite any expression of the
form \fIm1 m1args\f5|\fIm2 m2args\fR
as \fIm2 \f5{\fIm1 m1args\f5}\fIm2args\fR.
This occurs before any auto-conversions have been applied.
.PP
.I Command
may also be a
.IR "module block" ,
of the form:
.IP
.EX
{(\fIargtype\fR...\f5); \fIcommand arg\fR...\f5}
.EE
.PP
The
.I argtype
values given in the brackets
specify the types of the arguments expected by the module block;
these can be referred to in the arguments to
.I command
(and subexpressions thereof) with values of the form
.BR $1 ,
.BR $2 ,
etc.
For instance,
.IP
.EX
{(/string); echo $1} hello}
.EE
.PP
is exactly equivalent to:
.IP
.EX
{echo hello}
.EE
.PP
In a module block with no arguments, the argument declaration
section may be omitted.
.PP
.B Define
defines a new module in terms of previously declared
modules.
.I Name
(which must be an unqualified name)
gives the name of the
module to define, and
.I expr
is a module block giving the expression to evaluate when
.I name
is used. The usage of the module is taken from the types declared
in the module block; its return type is inferred from the return type
of
.IR expr .
All modules used in the evaluation of
.I expr
are evaluated when the definition takes place, so evaluation of
.I name
is unaffected if any modules it uses are later undeclared.
.PP
To show the complete form of an expression, after pipe
transformations and auto-conversions have been applied, and
module definitions expanded, use
.BR ${rewrite} ,
which returns the expression's canonical form
without actually executing it.
If
.I dsttype
is given, auto-conversions will be applied to try to
convert the result of
.I expression
to
.IR dsttype .
.B Rewrite
raises an error if it finds any declarations incompatible with
.IR expression
or if the final type cannot be converted successfully.
.PP
.I Alphabet
also provides some shell operations that give information
on its current state:
.B ${modules}
yields a list of all the currently declared module names
(including entries for both qualified and unqualified names);
.B ${types}
yields a list of all currently available types
(giving only the types in
.I typeset
if specified);
and
.B ${usage}
provides usage information on module
.IR qname ,
which need not be declared.
Additionally,
.B info
searches the module directories on all currently loaded typesets,
and prints usage information for everything it can find there,
along with information on all currently installed auto-conversions.
.PP
Finally,
.B clear
clears all existing declarations and definitions, and starts again
with a clean slate.
.SH EXAMPLE
.EX
load alphabet
type /string
type /fd
type /status
import /cat /filter
autoconvert string fd /read
autoconvert fd status {(fd); /print $1 1}
define wc {(fd); /filter $1 "{wc}}
- {cat /lib/polyhedra /dis/sh.dis | wc}
echo ${rewrite {cat /lib/polyhedra /dis/sh.dis | wc} status}
.EE
.SH SOURCE
.B /appl/alphabet/*.b
.br
.B /appl/alphabet/*/*.b
.SH BUGS
.I Alphabet
expressions involving external typesets and file descriptors cannot have
their I/O
redirected at the shell level. Unfortunately it is not possible
to provide a diagnostic when this occurs.
.SH SEE ALSO
.IR sh (1),
.IR alphabet (2),
.IR alphabet-main (1),
.IR alphabet-fs (1),
.IR alphabet-grid (1)