mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-18 21:29:19 +02:00
1317 lines
54 KiB
Racket
Executable file
1317 lines
54 KiB
Racket
Executable file
\; #lang scribble/manual
|
|
|
|
\title{Chibi-Scheme}
|
|
\author{Alex Shinn}
|
|
|
|
\centered{\smaller{Minimal Scheme Implementation for use as an Extension Language}}
|
|
\centered{\url{http://synthcode.com/wiki/chibi-scheme/}}
|
|
|
|
\section{Introduction}
|
|
|
|
Chibi-Scheme is a very small library with no external dependencies,
|
|
intended for use as an extension and scripting language in C programs.
|
|
In addition to support for lightweight VM-based threads, each VM
|
|
itself runs in an isolated heap allowing multiple VMs to run
|
|
simultaneously in different OS threads.
|
|
|
|
The default language is the R7RS (scheme base) library, with support
|
|
for all libraries from the small language. Support for additional
|
|
languages such as JavaScript, Go, Lua and Bash are planned for future
|
|
releases. Scheme is chosen as a substrate because its first class
|
|
continuations and guaranteed tail-call optimization makes implementing
|
|
other languages easy.
|
|
|
|
The system is designed in optional layers, beginning with a VM based
|
|
on a small set of opcodes, a set of primitives implemented in C, a
|
|
default language, a module system implementation, and a set of
|
|
standard modules. You can choose whichever layer suits your needs
|
|
best and customize the rest. Adding your own primitives or wrappers
|
|
around existing C libraries is easy with the C FFI.
|
|
|
|
Chibi is known to build and run on 32 and 64-bit Linux, FreeBSD,
|
|
DragonFly, OS X, iOS, Windows (under Cygwin) and Plan9.
|
|
|
|
\section{Installation}
|
|
|
|
To build, just run "make". This will provide a shared library
|
|
"libchibi-scheme", as well as a sample "chibi-scheme" command-line
|
|
repl. The "chibi-scheme-static" make target builds an equivalent
|
|
static executable. If your make doesn't support GNU make
|
|
conditionals, then you'll need to edit the top of the Makefile to
|
|
choose the appropriate settings. On Plan9 just run "mk". You can
|
|
test the build with "make test".
|
|
|
|
To install run "make install". If you want to try the executable out
|
|
without installing, you will probably need to set LD_LIBRARY_PATH,
|
|
depending on your platform. If you have an old version installed,
|
|
run "make uninstall" first, or manually delete the directory.
|
|
|
|
You can edit the file chibi/features.h for a number of settings,
|
|
mostly disabling features to make the executable smaller. You can
|
|
specify standard options directly as arguments to make, for example
|
|
|
|
\command{make CFLAGS=-Os CPPFLAGS=-DSEXP_USE_NO_FEATURES=1}
|
|
|
|
to optimize for size, or
|
|
|
|
\command{make LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include}
|
|
|
|
to compile against a library installed in /usr/local.
|
|
|
|
By default Chibi uses a custom, precise, non-moving GC (non-moving is
|
|
important so you can maintain references from C code). You can link
|
|
against the Boehm conservative GC by editing the features.h file, or
|
|
directly from make with:
|
|
|
|
\command{make SEXP_USE_BOEHM=1}
|
|
|
|
To compile a static executable, use
|
|
|
|
\command{make chibi-scheme-static SEXP_USE_DL=0}
|
|
|
|
To compile a static executable with all C libraries statically
|
|
included, first you need to create a clibs.c file, which can be done
|
|
with:
|
|
|
|
\command{make clibs.c}
|
|
|
|
or edited manually. Be sure to run this with a non-static
|
|
chibi-scheme. Then you can make the static executable with:
|
|
|
|
\command{
|
|
make -B chibi-scheme-static SEXP_USE_DL=0 CPPFLAGS=-DSEXP_USE_STATIC_LIBS
|
|
}
|
|
|
|
By default files are installed in /usr/local. You can optionally
|
|
specify a PREFIX for the installation directory:
|
|
|
|
\command{
|
|
make PREFIX=/path/to/install/
|
|
sudo make PREFIX=/path/to/install/ install
|
|
}
|
|
|
|
\subsection{Compile-Time Options}
|
|
|
|
The include file \ccode{"chibi/features.h"} describes a number of
|
|
C preprocessor values which can be enabled or disabled by setting to
|
|
1 or 0 respectively. For example, the above commands used the
|
|
features \ccode{SEXP_USE_BOEHM}, \ccode{SEXP_USE_DL} and
|
|
\ccode{SEXP_USE_STATIC_LIBS}. Many features are still experimental
|
|
and may be removed from future releases, but the important features
|
|
are listed below.
|
|
|
|
\itemlist[
|
|
\item{\ccode{SEXP_USE_BOEHM} - link with the Boehm GC instead of the native Chibi GC}
|
|
\item{\ccode{SEXP_USE_DL} - allow dynamic linking (enabled by default)}
|
|
\item{\ccode{SEXP_USE_STATIC_LIBS} - compile the standard C libs statically}
|
|
\item{\ccode{SEXP_USE_MODULES} - use the module system}
|
|
\item{\ccode{SEXP_USE_GREEN_THREADS} - use lightweight threads (enabled by default)}
|
|
\item{\ccode{SEXP_USE_SIMPLIFY} - use a simplification optimizer pass (enabled by default)}
|
|
\item{\ccode{SEXP_USE_BIGNUMS} - use bignums (enabled by default)}
|
|
\item{\ccode{SEXP_USE_FLONUMS} - use flonums (enabled by default)}
|
|
\item{\ccode{SEXP_USE_RATIOS} - use exact ratios (enabled by default)}
|
|
\item{\ccode{SEXP_USE_COMPLEX} - use complex numbers (enabled by default)}
|
|
\item{\ccode{SEXP_USE_UTF8_STRINGS} - Unicode support (enabled by default)}
|
|
\item{\ccode{SEXP_USE_NO_FEATURES} - disable almost all features}
|
|
]
|
|
|
|
\subsection{Installed Programs}
|
|
|
|
The command-line programs \ccode{chibi-scheme}, \ccode{chibi-doc} and
|
|
\ccode{chibi-ffi} are installed by default, along with manpages.
|
|
\ccode{chibi-scheme} provides a REPL and way to run scripts. Run -?
|
|
for a brief list of options, or see the man page for more details.
|
|
\ccode{chibi-doc} is the command-line interface to the literate
|
|
documentation system described in
|
|
\hyperlink["lib/chibi/scribble.html"]{(chibi scribble)}, and used to
|
|
build this manual. \ccode{chibi-ffi} is a tool to build wrappers for
|
|
C libraries, described in the FFI section below.
|
|
|
|
\section{Default Language}
|
|
|
|
\subsection{Scheme Standard}
|
|
|
|
The default language is the \scheme{(scheme base)} library from
|
|
\hyperlink["http://scheme-reports.org/"]{R7RS}, which is mostly a
|
|
superset of
|
|
\hyperlink["http://www.schemers.org/Documents/Standards/R5RS/HTML/"]{R5RS}.
|
|
|
|
The reader defaults to case-sensitive, like R6RS and R7RS but unlike
|
|
R5RS. The default configuration includes the full numeric tower:
|
|
fixnums, flonums, bignums, exact rationals and complex numbers, though
|
|
this can be customized at compile time.
|
|
|
|
Full continuations are supported, but currently continuations don't
|
|
take C code into account. This means that you can call from Scheme to
|
|
C and then from C to Scheme again, but continuations passing through
|
|
this chain may not do what you expect. The only higher-order C
|
|
functions (thus potentially running afoul of this) in the standard
|
|
environment are \scheme{load} and \scheme{eval}. The result of
|
|
invoking a continuation created by a different thread is also
|
|
currently unspecified.
|
|
|
|
In R7RS (and R6RS) semantics it is impossible to use two macros from
|
|
different modules which both use the same auxiliary keywords (like
|
|
\scheme{else} in \scheme{cond} forms) without renaming one of the
|
|
keywords. By default Chibi considers all top-level bindings
|
|
effectively unbound when matching auxiliary keywords, so this case
|
|
will "just work". This decision was made because the chance of
|
|
different modules using the same keywords seems more likely than user
|
|
code unintentionally matching a top-level keyword with a different
|
|
binding, however if you want to use R7RS semantics you can compile
|
|
with \ccode{SEXP_USE_STRICT_TOPLEVEL_BINDINGS=1}.
|
|
|
|
\scheme{load} is extended to accept an optional environment argument, like
|
|
\scheme{eval}. You can also \scheme{load} shared libraries in addition to
|
|
Scheme source files - in this case the function \cfun{sexp_init_library} is
|
|
automatically called with the following signature:
|
|
|
|
\ccode{
|
|
sexp_init_library(sexp context, sexp self, sexp_sint_t n, sexp environment,
|
|
const char* version, sexp_abi_identifier_t abi);
|
|
}
|
|
|
|
Note, as R7RS (and earlier reports) states, "in contrast to other
|
|
dialects of Lisp, the order of evaluation is unspecified [...]".
|
|
Chibi is one of the few implementations which use a right-to-left
|
|
evaluation order, which can be surprising to programmers coming from
|
|
other languages.
|
|
|
|
\subsection{Module System}
|
|
|
|
Chibi uses the R7RS module system natively, which is a simple static
|
|
module system in the style of the
|
|
\hyperlink["http://s48.org/"]{Scheme48} module system. As with most
|
|
features this is optional, and can be ignored or completely disabled
|
|
at compile time.
|
|
|
|
Modules names are hierarchical lists of symbols or numbers. A module
|
|
definition uses the following form:
|
|
|
|
\schemeblock{
|
|
(define-library (foo bar baz)
|
|
<library-declarations> ...)
|
|
}
|
|
|
|
where \var{<library-declarations>} can be any of
|
|
|
|
\schemeblock{
|
|
(export <id> ...) ;; specify an export list
|
|
(import <import-spec> ...) ;; specify one or more imports
|
|
(begin <expr> ...) ;; inline Scheme code
|
|
(include <file> ...) ;; load one or more files
|
|
(include-ci <file> ...) ;; as include, with case-folding
|
|
(include-shared <file> ...) ;; dynamic load a library
|
|
}
|
|
|
|
\var{<import-spec>} can either be a module name or any of
|
|
|
|
\schemeblock{
|
|
(only <import-spec> <id> ...)
|
|
(except <import-spec> <id> ...)
|
|
(rename <import-spec> (<from-id> <to-id>) ...)
|
|
(prefix <prefix-id> <import-spec>)
|
|
}
|
|
|
|
These forms perform basic selection and renaming of individual
|
|
identifiers from the given module. They may be composed to perform
|
|
combined selection and renaming.
|
|
|
|
Some modules can be statically included in the initial configuration,
|
|
and even more may be included in image files, however in general
|
|
modules are searched for in a module load path. The definition of the
|
|
module \scheme{(foo bar baz)} is searched for in the file
|
|
\scheme{"foo/bar/baz.sld"}. The default module path includes the
|
|
installed directories, \scheme{"."} and \scheme{"./lib"}. Additional
|
|
directories can be specified with the command-line options \ccode{-I}
|
|
and \ccode{-A} (see the command-line options below) or with the
|
|
\scheme{add-modue-directory} procedure at runtime. You can search for
|
|
a module file with \scheme{(find-module-file <file>)}, or load it with
|
|
\scheme{(load-module-file <file> <env>)}.
|
|
|
|
Within the module definition, files are loaded relative to the .sld
|
|
file, and are written with their extension (so you can use whatever
|
|
suffix you prefer - .scm, .ss, .sls, etc.).
|
|
|
|
Shared modules, on the other hand, should be specified \emph{without} the
|
|
extension - the correct suffix will be added portably (e.g. .so for Unix and
|
|
.dylib for OS X).
|
|
|
|
You may also use \scheme{cond-expand} and arbitrary macro expansions in a
|
|
module definition to generate \var{<module-declarations>}.
|
|
|
|
\subsection{Macro System}
|
|
|
|
\scheme{syntax-rules} macros are provided by default, with the extensions from
|
|
\hyperlink["http://srfi.schemers.org/srfi-46/srfi-46.html"]{SRFI-46}.
|
|
In addition, low-level hygienic macros are provided with a
|
|
syntactic-closures interface, including \scheme{sc-macro-transformer},
|
|
\scheme{rsc-macro-transformer}, and \scheme{er-macro-transformer}. A good
|
|
introduction to syntactic-closures can be found at
|
|
\url{http://community.schemewiki.org/?syntactic-closures}.
|
|
|
|
\scheme{identifier?}, \scheme{identifier->symbol}, \scheme{identifier=?}, and
|
|
\scheme{make-syntactic-closure} and \scheme{strip-syntactic-closures} are
|
|
also available.
|
|
|
|
\subsection{Types}
|
|
|
|
You can define new record types with
|
|
\hyperlink["http://srfi.schemers.org/srfi-9/srfi-9.html"]{SRFI-9}, or
|
|
inherited record types with
|
|
\hyperlink["http://srfi.schemers.org/srfi-99/srfi-99.html"]{SRFI-99}.
|
|
These are just syntactic sugar for the following more primitive type
|
|
constructors:
|
|
|
|
\schemeblock{
|
|
(register-simple-type <name-string> <parent> <num-fields>)
|
|
=> <type>
|
|
|
|
(make-type-predicate <opcode-name-string> <type>)
|
|
=> <opcode> ; takes 1 arg, returns #t iff that arg is of the type
|
|
|
|
(make-constructor <constructor-name-string> <type>)
|
|
=> <opcode> ; takes 0 args, returns a newly allocated instance of type
|
|
|
|
(make-getter <getter-name-string> <type> <field-index>)
|
|
=> <opcode> ; takes 1 args, retrieves the field located at the index
|
|
|
|
(make-setter <setter-name-string> <type> <field-index>)
|
|
=> <opcode> ; takes 2 args, sets the field located at the index
|
|
}
|
|
|
|
\subsection{Unicode}
|
|
|
|
Chibi supports Unicode strings, encoding them as utf8. This provides easy
|
|
interoperability with many C libraries, but means that \scheme{string-ref} and
|
|
\scheme{string-set!} are O(n), so they should be avoided in
|
|
performance-sensitive code.
|
|
|
|
In general you should use high-level APIs such as \scheme{string-map}
|
|
to ensure fast string iteration. String ports also provide a simple
|
|
way to efficiently iterate and construct strings, by looping over an
|
|
input string or accumulating characters in an output string.
|
|
|
|
The \scheme{in-string} and \scheme{in-string-reverse} iterators in the
|
|
\scheme{(chibi loop)} module will also iterate over strings
|
|
efficiently while hiding the low-level details.
|
|
|
|
In the event that you do need a low-level interface, such as when
|
|
writing your own iterator protocol, you should use the following
|
|
string cursor API instead of indexes.
|
|
|
|
\itemlist[
|
|
\item{\scheme{(string-cursor-start str)}
|
|
\p{returns a start cursor for the string}}
|
|
\item{\scheme{(string-cursor-end str)}
|
|
\p{returns a cursor one past the last valid cursor}}
|
|
\item{\scheme{(string-cursor-ref str cursor)}
|
|
\p{get the char at the given cursor}}
|
|
\item{\scheme{(string-cursor-next str cursor)}
|
|
\p{increment to the next cursor}}
|
|
\item{\scheme{(string-cursor-prev str cursor)}
|
|
\p{decrement to the previous cursor}}
|
|
\item{\scheme{(substring-cursor str cs1 [cs2])}
|
|
\p{take a substring from the given cursors}}
|
|
\item{\scheme{(string-cursor<? cs1 cs2)}
|
|
\p{cs1 is before cs2}}
|
|
\item{\scheme{(string-cursor<=? cs1 cs2)}
|
|
\p{cs1 is before or the same as cs2}}
|
|
\item{\scheme{(string-cursor=? cs1 cs2)}
|
|
\p{cs1 is the same as cs2}}
|
|
\item{\scheme{(string-cursor>? cs1 cs2)}
|
|
\p{cs1 is after cs2}}
|
|
\item{\scheme{(string-cursor>=? cs1 cs2)}
|
|
\p{cs1 is the same or after cs2}}
|
|
]
|
|
|
|
\section{Embedding in C}
|
|
|
|
\subsection{Quick Start}
|
|
|
|
To use Chibi-Scheme in a program you need to link against the
|
|
"libchibi-scheme" library and include the "eval.h" header file:
|
|
|
|
\ccode{#include <chibi/eval.h>}
|
|
|
|
All definitions begin with a "sexp_" prefix, or "SEXP_" for constants.
|
|
In addition to the prototypes and utility macros, this includes the
|
|
following type definitions:
|
|
|
|
\itemlist[
|
|
\item{\ctype{sexp} - an s-expression, used to represent all Scheme objects}
|
|
\item{\ctype{sexp_uint_t} - an unsigned integer using as many bits as sexp}
|
|
\item{\ctype{sexp_sint_t} - a signed integer using as many bits as sexp}
|
|
]
|
|
|
|
A simple program might look like:
|
|
|
|
\ccodeblock{
|
|
void dostuff(sexp ctx) {
|
|
/* declare and preserve local variables */
|
|
sexp_gc_var2(obj1, obj2);
|
|
sexp_gc_preserve2(ctx, obj1, obj2);
|
|
|
|
/* load a file containing Scheme code */
|
|
obj1 = sexp_c_string(ctx, "/path/to/source/file.scm", -1);
|
|
sexp_load(ctx, obj1, NULL);
|
|
|
|
/* eval a C string as Scheme code */
|
|
sexp_eval_string(ctx, "(some scheme expression)", -1, NULL);
|
|
|
|
/* construct a Scheme expression to eval */
|
|
obj1 = sexp_intern(ctx, "my-procedure", -1);
|
|
obj2 = sexp_cons(ctx, obj1, SEXP_NULL);
|
|
sexp_eval(ctx, obj2, NULL);
|
|
|
|
/* release the local variables */
|
|
sexp_gc_release2(ctx);
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
sexp ctx;
|
|
ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0);
|
|
sexp_load_standard_env(ctx, NULL, SEXP_SEVEN);
|
|
sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 0);
|
|
dostuff(ctx);
|
|
sexp_destroy_context(ctx);
|
|
}
|
|
}
|
|
|
|
Looking at \cfun{main}, \cfun{sexp_make_eval_context} and
|
|
\cfun{sexp_destroy_context} create and destroy a "context", which
|
|
manages the heap and VM state. The meaning of the arguments is
|
|
explained in detail below, but these values will give reasonable
|
|
defaults, in this case constructing an environment with the core
|
|
syntactic forms, opcodes, and standard C primitives.
|
|
|
|
This is still a fairly bare environment, so we call
|
|
\cfun{sexp_load_standard_env} to find and load the default
|
|
initialization file.
|
|
|
|
The resulting context can then be used to construct objects, call
|
|
functions, and most importantly evaluate code, as is done in
|
|
\cfun{dostuff}. The default garbage collector for Chibi is precise,
|
|
which means we need to declare and preserve references to any
|
|
temporary values we may generate, which is what the
|
|
\cmacro{sexp_gc_var2}, \cmacro{sexp_gc_preserve2} and
|
|
\cmacro{sexp_gc_release2} macros do (there are similar macros for
|
|
values 1-6). Precise GCs prevent a class of memory leaks (and
|
|
potential attackes based thereon), but if you prefer convenience then
|
|
Chibi can be compiled with a conservative GC and you can ignore these.
|
|
|
|
The interesting part is then the calls to \cfun{sexp_load},
|
|
\cfun{eval_string} and \cfun{eval} which evaluate code stored in
|
|
files, C strings, or represented as s-expressions respectively.
|
|
|
|
Destroying a context runs any finalizers for all objects in the heap
|
|
and then frees the heap memory (but has no effect on other contexts
|
|
you or other users of the library may have created).
|
|
|
|
\subsection{Contexts and Evaluation}
|
|
|
|
Contexts represent the state needed to perform evaluation. This includes
|
|
keeping track of the heap (when using precise GC), a default environment,
|
|
execution stack, and any global values. A program being evaluated in one
|
|
context may spawn multiple child contexts, such as when you call \scheme{eval},
|
|
and each child will share the same heap and globals. When using multiple
|
|
interpreter threads, each thread has its own context.
|
|
|
|
You can also create independent contexts with their own separate heaps. These
|
|
can run simultaneously in multiple OS threads without any need for
|
|
synchronization.
|
|
|
|
\itemlist[
|
|
|
|
\item{\ccode{sexp_make_context(sexp ctx, size_t size, size_t max_size)}
|
|
\p{
|
|
Creates a new context object. The context has no associated environment, and
|
|
so cannot be used for evaluation, but can be used to construct Scheme objects
|
|
and call primitive C functions on them.
|
|
|
|
If \var{ctx} is non-NULL it becomes the "parent" context. The resulting
|
|
context will share the same heap as its parent, and when using a precise GC
|
|
preserve any variables preserved by the parent, but the parent will not
|
|
preserve the child context by default. Typically you either preserve the child
|
|
manually or use it to perform a single sub-task then discard it and return to
|
|
using only the parent.
|
|
|
|
Otherwise, a new heap is allocated with \var{size} bytes, expandable to a
|
|
maximum of \var{max_size} bytes, using the system defaults if either is 0.
|
|
}}
|
|
|
|
\item{\ccode{sexp_make_eval_context(sexp ctx, sexp stack, sexp env, sexp_uint_t size, sexp_uint_t max_size)}
|
|
\p{
|
|
Similar to sexp_make_context, but also associates a stack, environment, and
|
|
additional globals necessary to evaluate code. Either or both of \var{stack}
|
|
and \var{env} may be NULL, in which case defaults will be generated. The
|
|
default environment includes the compiled-in C primitives, as well as the 10
|
|
core forms: \scheme{define}, \scheme{set!}, \scheme{lambda}, \scheme{if},
|
|
\scheme{begin}, \scheme{quote}, \scheme{syntax-quote}, \scheme{define-syntax},
|
|
\scheme{let-syntax}, and \scheme{letrec-syntax}.
|
|
}}
|
|
|
|
\item{\ccode{sexp_load_standard_env(sexp ctx, sexp env, sexp version)}
|
|
\p{
|
|
Loads the standard parameters for \var{env}, constructs the feature list from
|
|
pre-compiled defaults, and loads the installed initialization file for
|
|
\var{version}, which should be the value \var{SEXP_SEVEN}.
|
|
Also creates an \scheme{interaction-environment} parameter
|
|
and sets \var{env} itself to that.
|
|
}}
|
|
|
|
\item{\ccode{sexp_load_standard_ports(sexp ctx, sexp env, FILE* in, FILE* out, FILE* err, int leave_open)}
|
|
\p{
|
|
Creates \scheme{current-input-port}, \scheme{current-output-port}, and
|
|
\scheme{current-error-port} parameters from \var{in}, \var{out} and
|
|
\var{err}, and binds them in \var{env}. If \var{env} is \cvar{NULL}
|
|
the default context environment is used. Any of the \ctype{FILE*} may
|
|
be \cvar{NULL}, in which case the corresponding port is not set. If
|
|
\var{leave_open} is true, then the underlying \ctype{FILE*} is left
|
|
open after the Scheme port is closed, otherwise they are both closed
|
|
together.
|
|
}}
|
|
|
|
\item{\ccode{sexp_load(sexp ctx, sexp file, sexp env)}
|
|
\p{
|
|
Searches the installation path for the \var{file} and loads it in the
|
|
environment \var{env}. \var{file} may be a dynamic library or source code.
|
|
}}
|
|
|
|
\item{\ccode{sexp_eval(sexp ctx, sexp obj, sexp env)}
|
|
\p{
|
|
Evaluates \var{obj} as a source form in the environment \var{env} and
|
|
returns the result.
|
|
}}
|
|
|
|
\item{\ccode{sexp_eval_string(sexp ctx, const char* str, int len, sexp env)}
|
|
\p{
|
|
Reads a s-expression from the C string \var{str} (or the first \var{len} bytes
|
|
if \var{len} is non-negative), evaluates the resulting form in the environment
|
|
\var{env}, and returns the result.
|
|
}}
|
|
|
|
\item{\ccode{sexp_apply(sexp ctx, sexp proc, sexp args)}
|
|
\p{
|
|
Applies the procedure \var{proc} to the arguments in the list \var{args} and
|
|
returns the result.
|
|
}}
|
|
|
|
\item{\ccode{sexp_context_env(sexp ctx)}
|
|
\p{
|
|
Returns the current default environment associated with the context \var{ctx}.
|
|
}}
|
|
|
|
\item{\ccode{sexp_env_define(sexp ctx, sexp env, sexp sym, sexp val)}
|
|
\p{
|
|
Adds a new binding for \var{sym} in \var{env} with value \var{val}.
|
|
}}
|
|
|
|
\item{\ccode{sexp_env_ref(sexp env, sexp sym, sexp dflt)}
|
|
\p{
|
|
Returns the current binding of \var{sym} in \var{env}, or \var{dflt} if there
|
|
is no binding.
|
|
}}
|
|
|
|
\item{\ccode{sexp_parameter_ref(sexp ctx, sexp param)}
|
|
\p{
|
|
Returns the current dynamic value of the parameter \var{param} in the
|
|
given context.
|
|
}}
|
|
|
|
]
|
|
|
|
\subsection{Garbage Collection}
|
|
|
|
Chibi uses a precise garbage collector by default, which means when performing
|
|
multiple computations on the C side you must explicitly preserve any temporary
|
|
values. You can declare variables to be preserved with sexp_gc_var\italic{n},
|
|
for n from 1 to 6.\margin-note{You can declare additional macros for larger
|
|
values of n if needed.}
|
|
|
|
\ccode{
|
|
sexp_gc_var\italic{n}(obj\subscript{1}, obj\subscript{2}, ..., obj\subscript{n})
|
|
}
|
|
|
|
This is equivalent to the declaration
|
|
|
|
\ccode{
|
|
sexp obj\subscript{1}, obj\subscript{2}, ..., obj\subscript{n};
|
|
}
|
|
|
|
except it makes preservation possible. Because it is a declaration it must
|
|
occur at the beginning of your function, and because it includes assignments
|
|
(in the macro-expanded form) it should occur after all other declarations.
|
|
|
|
To preserve these variables for a given context, you can then use
|
|
sexp_gc_preserve\italic{n}:
|
|
|
|
\ccode{
|
|
sexp_gc_preserve\italic{n}(ctx, obj\subscript{1}, obj\subscript{2}, ..., obj\subscript{n})
|
|
}
|
|
|
|
This can be delayed in your code until you know a potentially memory-allocating
|
|
computation will be performed, but once you call sexp_gc_preserve\italic{n} it
|
|
\emph{must} be paired with a matching sexp_gc_release\italic{n}:
|
|
|
|
\ccode{
|
|
sexp_gc_release\italic{n}(ctx);
|
|
}
|
|
|
|
Note each of these have different signatures. sexp_gc_var\italic{n} just lists
|
|
the variables to be declared. sexp_gc_preserve\italic{n} prefixes these with
|
|
the context in which they are to be preserved, and sexp_gc_release\italic{n}
|
|
just needs the context.
|
|
|
|
A typical usage for these is:
|
|
|
|
\ccodeblock{
|
|
sexp foo(sexp ctx, sexp bar, sexp baz) {
|
|
/* variable declarations */
|
|
int i, j;
|
|
...
|
|
sexp_gc_var3(tmp1, tmp2, res);
|
|
|
|
/* asserts or other shortcut returns */
|
|
sexp_assert_type(ctx, sexp_barp, SEXP_BAR, bar);
|
|
sexp_assert_type(ctx, sexp_bazp, SEXP_BAZ, baz);
|
|
|
|
/* preserve the variables in ctx */
|
|
sexp_gc_preserve3(ctx, tmp1, tmp2, res);
|
|
|
|
/* perform your computations */
|
|
tmp1 = ...
|
|
tmp2 = ...
|
|
res = ...
|
|
|
|
/* release before returning */
|
|
sexp_gc_release3(ctx);
|
|
|
|
return res;
|
|
}
|
|
}
|
|
|
|
If compiled with the Boehm GC, sexp_gc_var\italic{n} just translates to the
|
|
plain declaration, while sexp_gc_preserve\italic{n} and
|
|
sexp_gc_release\italic{n} become noops.
|
|
|
|
When interacting with a garbage collection system from another
|
|
language, or communicating between different Chibi managed heaps, you
|
|
may want to manually ensure objects are preserved irrespective of any
|
|
references to it from other objects in the same heap. This can be
|
|
done with the \ccode{sexp_preserve_object} and
|
|
\ccode{sexp_release_object} utilities.
|
|
|
|
\ccode{
|
|
sexp_preserve_object(ctx, obj)
|
|
}
|
|
|
|
Increment the absolute reference count for \var{obj}. So long as the
|
|
reference count is above 0, \var{obj} will not be reclaimed even if
|
|
there are no references to it from other object in the Chibi managed
|
|
heap.
|
|
|
|
\ccode{
|
|
sexp_release_object(ctx, obj)
|
|
}
|
|
|
|
Decrement the absolute reference count for \var{obj}.
|
|
|
|
\subsection{API Index}
|
|
|
|
The above sections describe most everything you need for embedding in
|
|
a typical application, notably creating environments and evaluating
|
|
code from sexps, strings or files. The following sections expand on
|
|
additional macros and utilities for inspecting, accessing and creating
|
|
different Scheme types, and for performing port and string I/O.
|
|
|
|
Being able to convert from C string to sexp, evaluate it, and convert
|
|
the result back to a C string forms the basis of the C API. Because
|
|
Chibi is aimed primarily at minimal size, there are relatively few
|
|
other utilities or helpers. It is expected most high-level code will
|
|
be written in Scheme, and most low-level code will be written in pure,
|
|
Scheme-agnostic C and wrapped via the FFI.
|
|
|
|
\subsubsection{Type Predicates}
|
|
|
|
The sexp represents different Scheme types with the use of tag bits for
|
|
so-called "immediate" values, and a type tag for heap-allocated values. The
|
|
following predicates can be used to distinguish these types. Note the
|
|
predicates in C all end in "p". For efficiency they are implemented as macros,
|
|
and so may evaluate their arguments multiple times.
|
|
|
|
Note also that the non-immediate type checks will segfault if passed a
|
|
NULL value. At the Scheme level (and the return values of any
|
|
exported primitives) NULLs are never exposed, however some unexposed
|
|
values in C can in certain cases be NULL. If you're not sure you'll
|
|
need to check manually before applying the predicate.
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp_booleanp(obj)} - \var{obj} is \scheme{#t} or \scheme{#f}}
|
|
\item{\ccode{sexp_fixnump(obj)} - \var{obj} is an immediate integer}
|
|
\item{\ccode{sexp_flonump(obj)} - \var{obj} is an inexact real}
|
|
\item{\ccode{sexp_bignump(obj)} - \var{obj} is a heap-allocated integer}
|
|
\item{\ccode{sexp_integerp(obj)} - \var{obj} is an integer}
|
|
\item{\ccode{sexp_numberp(obj)} - \var{obj} is any kind of number}
|
|
\item{\ccode{sexp_charp(obj)} - \var{obj} is a character}
|
|
\item{\ccode{sexp_stringp(obj)} - \var{obj} is a string}
|
|
\item{\ccode{sexp_bytesp(obj)} - \var{obj} is a bytevector}
|
|
\item{\ccode{sexp_symbolp(obj)} - \var{obj} is a symbol}
|
|
\item{\ccode{sexp_idp(obj)} - \var{obj} is a symbol or hygienic identifier}
|
|
\item{\ccode{sexp_nullp(obj)} - \var{obj} is the null value}
|
|
\item{\ccode{sexp_pairp(obj)} - \var{obj} is a pair}
|
|
\item{\ccode{sexp_vectorp(obj)} - \var{obj} is a vector}
|
|
\item{\ccode{sexp_iportp(obj)} - \var{obj} is an input port}
|
|
\item{\ccode{sexp_oportp(obj)} - \var{obj} is an output port}
|
|
\item{\ccode{sexp_portp(obj)} - \var{obj} is any kind of port}
|
|
\item{\ccode{sexp_procedurep(obj)} - \var{obj} is a procedure}
|
|
\item{\ccode{sexp_opcodep(obj)} - \var{obj} is a primitive opcode}
|
|
\item{\ccode{sexp_applicablep(obj)} - \var{obj} is valid as the first arg to apply}
|
|
\item{\ccode{sexp_typep(obj)} - \var{obj} is a type}
|
|
\item{\ccode{sexp_exceptionp(obj)} - \var{obj} is an exception}
|
|
\item{\ccode{sexp_contextp(obj)} - \var{obj} is a context}
|
|
\item{\ccode{sexp_envp(obj)} - \var{obj} is an environment}
|
|
\item{\ccode{sexp_corep(obj)} - \var{obj} is a special form}
|
|
\item{\ccode{sexp_macrop(obj)} - \var{obj} is a macro}
|
|
\item{\ccode{sexp_synclop(obj)} - \var{obj} is a syntactic closure}
|
|
\item{\ccode{sexp_bytecodep(obj)} - \var{obj} is compiled bytecode}
|
|
\item{\ccode{sexp_cpointerp(obj)} - \var{obj} is an opaque C pointer}
|
|
]
|
|
|
|
\subsubsection{Constants}
|
|
|
|
The following shortcuts for various immediate values are available.
|
|
|
|
\itemlist[
|
|
\item{\ccode{SEXP_FALSE} - the false boolean}
|
|
\item{\ccode{SEXP_TRUE} - the true boolean}
|
|
\item{\ccode{SEXP_NULL} - the empty list}
|
|
\item{\ccode{SEXP_EOF} - the end-of-file object}
|
|
\item{\ccode{SEXP_VOID} - an undefined value often returned by mutators}
|
|
\item{\ccode{SEXP_ZERO} - shortcut for sexp_make_fixnum(0)}
|
|
\item{\ccode{SEXP_ONE} - shortcut for sexp_make_fixnum(1)}
|
|
\item{...}
|
|
\item{\ccode{SEXP_TEN} - shortcut for sexp_make_fixnum(10)}
|
|
\item{\ccode{SEXP_NEG_ONE} - shortcut for sexp_make_fixnum(-1)}
|
|
]
|
|
|
|
\subsubsection{String Handling}
|
|
|
|
Scheme strings are length bounded C strings which can be accessed with
|
|
the following macros:
|
|
|
|
\itemlist[
|
|
\item{\ccode{char* sexp_string_data(sexp s)} - the raw bytes of the string}
|
|
\item{\ccode{sexp_uint_t sexp_string_size(sexp s)} - the number of raw bytes in the string}
|
|
\item{\ccode{sexp_uint_t sexp_string_length(sexp s)} - the number of characters encoded in \var{s}}
|
|
]
|
|
|
|
Currently all Scheme strings also happen to be NULL-terminated, but
|
|
you should not rely on this and be sure to use the size as a bounds
|
|
check. The runtime does not prevent embedded NULLs inside strings,
|
|
however data after the NULL may be ignored.
|
|
|
|
By default (unless you compile with -DSEXP_USE_UTF8_STRING=0), strings
|
|
are interpreted as utf8 encoded on the Scheme side, as describe in
|
|
section Unicode above. In many cases you can ignore this on the C
|
|
side and just treat the string as an opaque sequence of bytes.
|
|
However, if you need to you can use the following macros to safely
|
|
access the contents of the string regardless of the options Chibi was
|
|
compiled with:
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp sexp_string_ref(sexp ctx, sexp s, sexp i)} - returns the character at index i}
|
|
\item{\ccode{sexp sexp_string_set(sexp ctx, sexp s, sexp i, sexp ch)} - sets the character at index i}
|
|
\item{\ccode{sexp sexp_string_cursor_ref(sexp ctx, sexp s, sexp i)} - returns the character at raw offset i (a fixnum)}
|
|
\item{\ccode{sexp sexp_string_cursor_set(sexp ctx, sexp s, sexp i, sexp ch)} - sets the character at raw offset i (a fixnum)}
|
|
\item{\ccode{sexp sexp_string_cursor_next(sexp s, sexp i)} - returns the next cursor after raw offset \var{i}}
|
|
\item{\ccode{sexp sexp_string_cursor_prev(sexp s, sexp i)} - returns the previous cursor before raw offset \var{i}}
|
|
\item{\ccode{sexp sexp_substring(sexp ctx, sexp s, sexp i, sexp j)} - returns the substring between indices \var{i} and \var{j}}
|
|
\item{\ccode{sexp sexp_substring_cursor(sexp ctx, sexp s, sexp i, sexp j)} - returns the substring between raw offsets \var{i} and \var{j}}
|
|
]
|
|
|
|
When UTF8 support is not compiled in the cursor and non-cursor
|
|
variants are equivalent.
|
|
|
|
\subsubsection{Accessors}
|
|
|
|
The following macros provide access to the different components of the
|
|
Scheme types. They do no type checking, essentially translating
|
|
directly to pointer offsets, so you should be sure to use the above
|
|
predicates to check types first. They only evaluate their arguments
|
|
once.
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp_make_boolean(n)} - \scheme{#f} if \var{n} is 0, \scheme{#t} otherwise}
|
|
\item{\ccode{sexp_unbox_boolean(obj)} - 1 if \var{obj} is \scheme{#t}, 0 otherwise}
|
|
\item{\ccode{sexp_make_fixnum(n)} - creates a new fixnum representing int \var{n}}
|
|
\item{\ccode{sexp_unbox_fixnum(obj)} - converts a fixnum to a C integer}
|
|
\item{\ccode{sexp_make_character(ch)} - creates a new character representing char \var{ch}}
|
|
\item{\ccode{sexp_unbox_character(obj)} - converts a character to a C char}
|
|
\item{\ccode{sexp_car(pair)} - the car of \var{pair}}
|
|
\item{\ccode{sexp_cdr(pair)} - the cdr of \var{pair}}
|
|
\item{\ccode{sexp_ratio_numerator(q)} - the numerator of the ratio \var{q}}
|
|
\item{\ccode{sexp_ratio_denominator(q)} - the denominator of the ratio \var{q}}
|
|
\item{\ccode{sexp_complex_real(z)} - the real part of the complex \var{z}}
|
|
\item{\ccode{sexp_complex_imag(z)} - the imaginary part of the complex \var{z}}
|
|
\item{\ccode{sexp_string_length(str)} - the byte length of \var{str} as an int}
|
|
\item{\ccode{sexp_string_ref(str, i)} - the \var{i}'th byte of string \var{str}}
|
|
\item{\ccode{sexp_string_set(str, i, ch)} - set the \var{i}'th byte of string \var{str}}
|
|
\item{\ccode{sexp_bytes_length(bv)} - the length of \var{bv} as an int}
|
|
\item{\ccode{sexp_bytes_data(bv)} - the raw char* data of \var{bv}}
|
|
\item{\ccode{sexp_vector_length(vec)} - the length of \var{vec} as an int}
|
|
\item{\ccode{sexp_vector_ref(vec, i)} - the \var{i}'th object of vector \var{vec}}
|
|
\item{\ccode{sexp_vector_set(vec, i, obj)} - set the \var{i}'th object of vector \var{vec}}
|
|
\item{\ccode{sexp_bytes_length(bv)} - the number of bytes in bytevector \var{bv}}
|
|
\item{\ccode{sexp_bytes_ref(bv, i)} - the \var{i}'th byte of bytevector \var{bv}}
|
|
\item{\ccode{sexp_bytes_set(bv, i, k)} - set the \var{i}'th byte of bytevector \var{bv}}
|
|
]
|
|
|
|
\subsubsection{Constructors}
|
|
|
|
Constructors allocate memory and so must be passed a context argument.
|
|
Any of these may fail and return the OOM exception object.
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp_cons(sexp ctx, sexp obj1, sexp obj2)} - create a new pair whose car is \var{obj1} and whose cdr is \var{obj2}}
|
|
\item{\ccode{sexp_list1(sexp ctx, sexp obj)} - alias for sexp_cons(ctx, obj, SEXP_NULL)}
|
|
\item{\ccode{sexp_list2(sexp ctx, sexp obj1, sexp obj2)} - create a list of two elements}
|
|
\item{\ccode{sexp_make_string(sexp ctx, sexp len, sexp ch)} - create a new Scheme string of \var{len} characters, all initialized to \var{ch}}
|
|
\item{\ccode{sexp_c_string(sexp ctx, const char* str, int len)} - create a new Scheme string copying the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).}
|
|
\item{\ccode{sexp_intern(sexp ctx, const char* str, int len)} - interns a symbol from the first \var{len} characters of the C string \var{str}. If \var{len} is -1, uses strlen(\var{str}).}
|
|
\item{\ccode{sexp_make_bytes(sexp ctx, sexp len, sexp i)} - create a new Scheme bytevector of \var{len} bytes, all initialized to \var{i}}
|
|
\item{\ccode{sexp_make_vector(sexp ctx, sexp len, sexp obj)} - create a new vector of \var{len} elements, all initialized to \var{obj}}
|
|
\item{\ccode{sexp_make_integer(sexp ctx, sexp_sint_t n)} - create an integer, heap allocating as a bignum if needed}
|
|
\item{\ccode{sexp_make_unsigned_integer(sexp ctx, sexp_uint_t n)} - create an unsigned integer, heap allocating as a bignum if needed}
|
|
]
|
|
|
|
\subsubsection{I/O}
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp_read(sexp ctx, sexp in)} - read a single datum from port \var{in}}
|
|
\item{\ccode{sexp_write(sexp ctx, sexp obj, sexp out)} - write \var{obj} to port \var{out}}
|
|
\item{\ccode{sexp_write_string(sexp ctx, char* str, sexp out)} - write the characters in \var{str} to port \var{out}}
|
|
\item{\ccode{sexp_display(sexp ctx, sexp obj, sexp out)} - display \var{obj} to port \var{out}}
|
|
\item{\ccode{sexp_newline(sexp ctx, sexp out)} - write a newline to port \var{out}}
|
|
\item{\ccode{sexp_print_exception(sexp ctx, sexp exn, sexp out)} - print an error message for \var{exn} to port \var{out}}
|
|
\item{\ccode{sexp_current_input_port(sexp ctx)} - the \scheme{current-input-port}}
|
|
\item{\ccode{sexp_current_output_port(sexp ctx)} - the \scheme{current-output-port}}
|
|
\item{\ccode{sexp_current_error_port(sexp ctx)} - the \scheme{current-error-port}}
|
|
\item{\ccode{sexp_debug(sexp ctx, char* msg, sexp obj)} - write \var{obj} with a debug message prefix to \scheme{current-error-port}}
|
|
\item{\ccode{sexp_read_from_string(sexp ctx, char* str, int len)} - read a single datum from \var{str}, using at most \var{len} bytes if \var{len} is non-negative}
|
|
\item{\ccode{sexp_write_to_string(sexp ctx, sexp obj)} - return a Scheme string representation of \var{obj}}
|
|
\item{\ccode{sexp_open_input_string(sexp ctx, sexp str)} - equivalent to \scheme{open-input-string}}
|
|
\item{\ccode{sexp_open_output_string(sexp ctx)} - equivalent to \scheme{open-output-string}}
|
|
\item{\ccode{sexp_get_output_string(sexp ctx, sexp port)} - equivalent to \scheme{open-output-string}}
|
|
]
|
|
|
|
\subsubsection{Utilities}
|
|
|
|
\itemlist[
|
|
\item{\ccode{sexp_equalp(sexp ctx, sexp x, sexp y)} - \scheme{equal?}}
|
|
\item{\ccode{sexp_length(sexp ctx, sexp ls)} - \scheme{length}}
|
|
\item{\ccode{sexp_listp(sexp ctx, sexp x)} - \scheme{list?}}
|
|
\item{\ccode{sexp_memq(sexp ctx, sexp x, sexp ls)} - \scheme{memq}}
|
|
\item{\ccode{sexp_assq(sexp ctx, sexp x, sexp ls)} - \scheme{assq}}
|
|
\item{\ccode{sexp_reverse(sexp ctx, sexp ls)} - \scheme{reverse}}
|
|
\item{\ccode{sexp_nreverse(sexp ctx, sexp ls)} - \scheme{reverse!}}
|
|
\item{\ccode{sexp_append2(sexp ctx, sexp ls)} - \scheme{append} for two arguments}
|
|
\item{\ccode{sexp_copy_list(sexp ctx, sexp ls)} - return a shallow copy of \var{ls}}
|
|
\item{\ccode{sexp_list_to_vector(sexp ctx, sexp ls)} - \scheme{list->vector}}
|
|
\item{\ccode{sexp_symbol_to_string(sexp ctx, sexp sym)} - \scheme{symbol->string}}
|
|
\item{\ccode{sexp_string_to_symbol(sexp ctx, sexp str)} - \scheme{string->symbol}}
|
|
\item{\ccode{sexp_string_to_number(sexp ctx, sexp str)} - \scheme{string->number}}
|
|
]
|
|
|
|
\subsection{Exceptions}
|
|
|
|
Exceptions can be created with the following:
|
|
|
|
\itemlist[
|
|
|
|
\item{\ccode{sexp sexp_make_exception (sexp ctx, sexp kind, sexp message, sexp irritants, sexp procedure, sexp source)}
|
|
\p{Create an exception of the given \var{kind} (a symbol), with the
|
|
string \var{message}, and \var{irritants} list. \var{procedure} and
|
|
\var{source} provide information about the error location. From a C
|
|
function, \var{procedure} should generally be \ccode{self}.}}
|
|
|
|
\item{\ccode{sexp sexp_user_exception (sexp ctx, sexp self, const char *msg, sexp x)}
|
|
\p{Shortcut for an exception of kind \ccode{user}, with the given message and single irritant.}}
|
|
|
|
\item{\ccode{sexp sexp_type_exception (sexp ctx, sexp self, sexp_uint_t type_id, sexp x)}
|
|
\p{Shortcut for an exception of kind \ccode{type}, where \var{x} was
|
|
expected to be of type \var{type_id} but wasn't.}}
|
|
|
|
\item{\ccode{sexp sexp_xtype_exception (sexp ctx, sexp self, const char *msg, sexp x)}
|
|
\p{Shortcut for an exception of kind \ccode{type}, for more general
|
|
domain errors, where \var{x} failed to meet the restrictions in \var{msg}.}}
|
|
|
|
]
|
|
|
|
Returning an exception from a C function by default \emph{raises} that
|
|
exception in the VM. If you want to pass an exception as a first
|
|
class value, you have to wrap it first:
|
|
|
|
\ccode{sexp sexp_maybe_wrap_error (sexp ctx, sexp obj)}
|
|
|
|
\subsection{Customizing}
|
|
|
|
You can add your own types and primitives with the following functions.
|
|
|
|
\itemlist[
|
|
|
|
\item{\ccode{sexp sexp_define_foreign(sexp ctx, sexp env, const char* name, int num_args, sexp_proc1 func)}
|
|
\p{
|
|
Defines a new primitive procedure with the name \var{name} in the
|
|
environment \var{env}. The procedure takes \var{num_args} arguments
|
|
and passes them to the C function \var{func}. The C function must
|
|
take the standard calling convention:
|
|
|
|
\ccode{sexp func(sexp ctx, sexp self, sexp n, sexp arg\sub{1}, ..., sexp arg\sub{num_args})}
|
|
|
|
where \var{ctx} is the current context, \var{self} is the procedure
|
|
itself, and \var{n} is the number of arguments passed.
|
|
|
|
\var{func} is responsible for checking its own argument types.
|
|
}}
|
|
|
|
\item{\ccode{sexp sexp_define_foreign_opt(sexp ctx, sexp env, const char* name, int num_args, sexp_proc1 func, sexp dflt)}
|
|
\p{
|
|
Equivalent to \cfun{sexp_define_foreign}, except the final argument is
|
|
optional and defaults to the value \var{dflt}.
|
|
}}
|
|
|
|
\item{\ccode{sexp sexp_define_foreign_param(sexp ctx, sexp env, const char* name, int num_args, sexp_proc1 func, const char* param)}
|
|
\p{
|
|
Equivalent to \cfun{sexp_define_foreign_opt}, except instead of a fixed
|
|
default argument \var{param} should be the name of a parameter bound in
|
|
\var{env}.
|
|
}}
|
|
|
|
\item{\ccode{sexp sexp_register_simple_type(sexp ctx, sexp name, sexp parent, sexp slots)}
|
|
\p{
|
|
Defines a new simple record type having \var{slots} new slots in addition
|
|
to any inherited from the parent type \var{parent}. If \var{parent} is false,
|
|
inherits from the default \var{object} record type.
|
|
}}
|
|
|
|
]
|
|
|
|
See the C FFI for an easy way to automate adding bindings for C
|
|
functions.
|
|
|
|
\section{C FFI}
|
|
|
|
The "chibi-ffi" script reads in the C function FFI definitions from an
|
|
input file and outputs the appropriate C wrappers into a file with the
|
|
same base name and the ".c" extension. You can then compile that C
|
|
file into a shared library:
|
|
|
|
\command{
|
|
chibi-ffi file.stub
|
|
cc -fPIC -shared file.c -lchibi-scheme
|
|
}
|
|
|
|
(or using whatever flags are appropriate to generate shared libs on
|
|
your platform) and the generated .so file can be loaded directly with
|
|
\scheme{load}, or portably using \scheme{(include-shared "file")} in a
|
|
module definition (note that include-shared uses no suffix).
|
|
|
|
The goal of this interface is to make access to C types and functions
|
|
easy, without requiring the user to write any C code. That means the
|
|
stubber needs to be intelligent about various C calling conventions
|
|
and idioms, such as return values passed in actual parameters.
|
|
Writing C by hand is still possible, and several of the core modules
|
|
provide C interfaces directly without using the stubber.
|
|
|
|
\subsection{Includes and Initializations}
|
|
|
|
\itemlist[
|
|
\item{\scheme{(c-include header)} - includes the file \var{header}}
|
|
\item{\scheme{(c-system-include header)} - includes the system file \var{header}}
|
|
\item{\scheme{(c-declare args ...)} - outputs \var{args} directly in the top-level C source}
|
|
\item{\scheme{(c-init args ...)} - evaluates \var{args} as C code after all other library initializations have been performed, with \cvar{ctx} and \cvar{env} in scope}
|
|
]
|
|
|
|
\subsection{Struct Interface}
|
|
|
|
C structs can be bound as Scheme types with the
|
|
\scheme{define-c-struct} form:
|
|
|
|
\schemeblock{
|
|
(define-c-struct struct_name
|
|
[predicate: predicate-name]
|
|
[constructor: constructor-name]
|
|
[finalizer: c_finalizer_name]
|
|
(type c_field_name getter-name setter-name) ...)
|
|
}
|
|
|
|
\var{struct_name} should be the name of a C struct type. If provided,
|
|
\var{predicate-name} is bound to a procedure which takes one object
|
|
and returns \scheme{#t} iff the object is of type \var{struct_name}.
|
|
|
|
If provided, \var{constructor-name} is bound to a procedure of zero
|
|
arguments which creates and returns a newly allocated instance of the
|
|
type.
|
|
|
|
If a finalizer is provided, \var{c_finalizer_name} must be a C
|
|
function which takes one argument, a pointer to the struct, and
|
|
performs any cleanup or freeing of resources necessary.
|
|
|
|
The remaining slots are similar to the
|
|
\hyperlink["http://srfi.schemers.org/srfi-9/srfi-9.html"]{SRFI-9} syntax,
|
|
except they are prefixed with a C type (described below). The
|
|
\var{c_field_name} should be a field name of \var{struct_name}.
|
|
\var{getter-name} will then be bound to a procedure of one argument, a
|
|
\{struct_name} type, which returns the given field. If provided,
|
|
\var{setter-name} will be bound to a procedure of two arguments to
|
|
mutate the given field.
|
|
|
|
The variants \scheme{define-c-class} and \scheme{define-c-union} take
|
|
the same syntax but define types with the \ccode{class} and
|
|
\ccode{union} keywords respectively. \scheme{define-c-type} just
|
|
defines accessors to an opaque type without any specific struct-like
|
|
keyword.
|
|
|
|
\schemeblock{
|
|
;; Example: the struct addrinfo returned by getaddrinfo.
|
|
|
|
(c-system-include "netdb.h")
|
|
|
|
(define-c-struct addrinfo
|
|
finalizer: freeaddrinfo
|
|
predicate: address-info?
|
|
(int ai_family address-info-family)
|
|
(int ai_socktype address-info-socket-type)
|
|
(int ai_protocol address-info-protocol)
|
|
((link sockaddr) ai_addr address-info-address)
|
|
(size_t ai_addrlen address-info-address-length)
|
|
((link addrinfo) ai_next address-info-next))
|
|
}
|
|
|
|
\subsection{Function and Constant Interface}
|
|
|
|
C functions are defined with:
|
|
|
|
\scheme{(define-c return-type name-spec (arg-type ...))}
|
|
|
|
where \var{name-space} is either a symbol name, or a list of
|
|
\scheme{(scheme-name c_name)}. If just a symbol is used, the C name
|
|
is generated automatically by replacing any dashes (-) in the Scheme
|
|
name with underscores (_).
|
|
|
|
Each \var{arg-type} is a type suitable for input validation and
|
|
conversion as discussed below.
|
|
|
|
\schemeblock{
|
|
;; Example: define connect(2) in Scheme
|
|
(define-c int connect (int sockaddr int))
|
|
}
|
|
|
|
Constants can be defined with:
|
|
|
|
\scheme{(define-c-const type name-space)}
|
|
|
|
where \var{name-space} is the same form as in \scheme{define-c}. This
|
|
defines a Scheme variable with the same value as the C constant.
|
|
|
|
\schemeblock{
|
|
;; Example: define address family constants in Scheme
|
|
(define-c-const int (address-family/unix "AF_UNIX"))
|
|
(define-c-const int (address-family/inet "AF_INET"))
|
|
}
|
|
|
|
\subsection{C Types}
|
|
|
|
\subsubsection{Basic Types}
|
|
|
|
\itemlist[
|
|
\item{\rawcode{void}}
|
|
\item{\rawcode{boolean}}
|
|
\item{\rawcode{char}}
|
|
\item{\rawcode{sexp} (no conversions)}
|
|
]
|
|
|
|
\subsubsection{Integer Types}
|
|
|
|
\itemlist[
|
|
\item{\rawcode{signed-char}}
|
|
\item{\rawcode{short}}
|
|
\item{\rawcode{int}}
|
|
\item{\rawcode{long}}
|
|
\item{\rawcode{unsigned-char}}
|
|
\item{\rawcode{unsigned-short}}
|
|
\item{\rawcode{unsigned-int}}
|
|
\item{\rawcode{unsigned-long}}
|
|
\item{\rawcode{size_t}}
|
|
\item{\rawcode{pid_t}}
|
|
\item{\rawcode{uid_t}}
|
|
\item{\rawcode{gid_t}}
|
|
\item{\rawcode{time_t} (in seconds, but using the chibi epoch of 2010/01/01)}
|
|
\item{\rawcode{errno} (as a return type returns \scheme{#f} on error)}
|
|
]
|
|
|
|
\subsubsection{Float Types}
|
|
|
|
\itemlist[
|
|
\item{\rawcode{float}}
|
|
\item{\rawcode{double}}
|
|
\item{\rawcode{long-double}}
|
|
]
|
|
|
|
\subsubsection{String Types}
|
|
|
|
\itemlist[
|
|
\item{\rawcode{string} - a null-terminated char*}
|
|
\item{\rawcode{env-string} - a \rawcode{VAR=VALUE} string represented as a \scheme{(VAR . VALUE)} pair in Scheme}
|
|
\item{\scheme{(array char)} is equivalent to \rawcode{string}}
|
|
]
|
|
|
|
\subsubsection{Port Types}
|
|
|
|
\itemlist[
|
|
\item{\rawcode{input-port}}
|
|
\item{\rawcode{output-port}}
|
|
]
|
|
|
|
\subsubsection{Struct Types}
|
|
|
|
Struct types are by default just referred to by the bare
|
|
\var{struct_name} from \scheme{define-c-struct}, and it is assumed you
|
|
want a pointer to that type. To refer to the full struct, use the
|
|
struct modifier, as in \scheme{(struct struct-name)}.
|
|
|
|
\subsubsection{Type modifiers}
|
|
|
|
Any type may also be written as a list of modifiers followed by the
|
|
type itself. The supported modifiers are:
|
|
|
|
\itemlist[
|
|
|
|
\item{\rawcode{const}
|
|
\p{Prepends the "const" C type modifier.
|
|
As a return or result parameter, makes non-immediates immutable.}}
|
|
|
|
\item{\rawcode{free}
|
|
\p{It's Scheme's responsibility to "free" this resource.
|
|
As a return or result parameter, registers the freep flag
|
|
this causes the type finalizer to be run when GCed.}}
|
|
|
|
\item{\rawcode{maybe-null}
|
|
\p{This pointer type may be NULL.
|
|
As a result parameter, NULL is translated to #f
|
|
normally this would just return a wrapped NULL pointer.
|
|
As an input parameter, #f is translated to NULL
|
|
normally this would be a type error.}}
|
|
|
|
\item{\rawcode{pointer}
|
|
\p{Create a pointer to this type.
|
|
As a return parameter, wraps the result in a vanilla cpointer.
|
|
As a result parameter, boxes then unboxes the value.}}
|
|
|
|
\item{\rawcode{reference}
|
|
\p{A stack-allocated pointer to this type.
|
|
As a result parameter, passes a stack-allocated pointer to
|
|
the value, then returns the dereferenced pointer.}}
|
|
|
|
\item{\rawcode{struct}
|
|
\p{Treat this struct type as a struct, not a pointer.
|
|
As an input parameter, dereferences the pointer.
|
|
As a type field, indicates a nested struct.}}
|
|
|
|
\item{\rawcode{link}
|
|
\p{Add a gc link.
|
|
As a field getter, link to the parent object, so the
|
|
parent won't be GCed so long as we have a reference
|
|
to the child. This behavior is automatic for nested structs.}}
|
|
|
|
\item{\rawcode{result}
|
|
\p{Return a result in this parameter.
|
|
If there are multiple results (including the return type),
|
|
they are all returned in a list.
|
|
If there are any result parameters, a return type
|
|
of errno returns #f on failure, and as eliminated
|
|
from the list of results otherwise.}}
|
|
|
|
\item{\scheme{(value <expr>)}
|
|
\p{Specify a fixed value.
|
|
As an input parameter, this parameter is not provided
|
|
in the Scheme API but always passed as <expr>.}}
|
|
|
|
\item{\scheme{(default <expr>)}
|
|
\p{Specify a default value.
|
|
As the final input parameter, makes the Scheme parameter
|
|
optional, defaulting to <expr>.}}
|
|
|
|
\item{\scheme{(array <type> [<length>])}
|
|
\p{An array type.
|
|
Length must be specified for return and result parameters.
|
|
If specified, length can be either an integer, indicating a fixed size,
|
|
or the symbol null, indicating a NULL-terminated array.}}
|
|
|
|
]
|
|
|
|
\section{Standard Modules}
|
|
|
|
A number of SRFIs are provided in the default installation. Note that
|
|
SRFIs 0, 6, 23, 46 and 62 are built into the default environment so
|
|
there's no need to import them. SRFI 22 is available with the "-r"
|
|
command-line option. This list includes popular SRFIs or SRFIs used
|
|
in standard Chibi modules
|
|
|
|
\itemlist[
|
|
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-0/srfi-0.html"]{(srfi 0) - cond-expand}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-1/srfi-1.html"]{(srfi 1) - list library}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-2/srfi-2.html"]{(srfi 2) - and-let*}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-6/srfi-6.html"]{(srfi 6) - basic string ports}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-8/srfi-8.html"]{(srfi 8) - receive}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-9/srfi-9.html"]{(srfi 9) - define-record-type}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-11/srfi-11.html"]{(srfi 11) - let-values/let*-values}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-16/srfi-16.html"]{(srfi 16) - case-lambda}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-18/srfi-18.html"]{(srfi 18) - multi-threading support}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-22/srfi-22.html"]{(srfi 22) - running scheme scripts on Unix}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-23/srfi-23.html"]{(srfi 23) - error reporting mechanism}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-26/srfi-26.html"]{(srfi 26) - cut/cute partial application}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-27/srfi-27.html"]{(srfi 27) - sources of random bits}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-33/srfi-33.html"]{(srfi 33) - bitwise operators}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-38/srfi-38.html"]{(srfi 38) - read/write shared structures}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-39/srfi-39.html"]{(srfi 39) - parameter objects}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-46/srfi-46.html"]{(srfi 46) - basic syntax-rules extensions}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-55/srfi-55.html"]{(srfi 55) - require-extension}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-62/srfi-62.html"]{(srfi 62) - s-expression comments}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-69/srfi-69.html"]{(srfi 69) - basic hash tables}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-95/srfi-95.html"]{(srfi 95) - sorting and merging}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-98/srfi-98.html"]{(srfi 98) - environment access}}
|
|
\item{\hyperlink["http://srfi.schemers.org/srfi-99/srfi-99.html"]{(srfi 99) - ERR5RS records}}
|
|
|
|
]
|
|
|
|
Additional non-standard modules are put in the \scheme{(chibi)} module
|
|
namespace.
|
|
|
|
\itemlist[
|
|
|
|
\item{\hyperlink["lib/chibi/ast.html"]{(chibi ast) - Abstract Syntax Tree and other internal data types}}
|
|
|
|
\item{\hyperlink["lib/chibi/config.html"]{(chibi config) - General configuration management}}
|
|
|
|
\item{\hyperlink["lib/chibi/disasm.html"]{(chibi disasm) - Disassembler for the virtual machine}}
|
|
|
|
\item{\hyperlink["lib/chibi/equiv.html"]{(chibi equiv) - A version of \scheme{equal?} which is guaranteed to terminate}}
|
|
|
|
\item{\hyperlink["lib/chibi/filesystem.html"]{(chibi filesystem) - Interface to the filesystem and file descriptor objects}}
|
|
|
|
\item{\hyperlink["lib/chibi/generic.html"]{(chibi generic) - Generic methods for CLOS-style object oriented programming}}
|
|
|
|
\item{\hyperlink["lib/chibi/heap-stats.html"]{(chibi heap-stats) - Utilities for gathering statistics on the heap}}
|
|
|
|
\item{\hyperlink["lib/chibi/io.html"]{(chibi io) - Various I/O extensions and custom ports}}
|
|
|
|
\item{\hyperlink["lib/chibi/loop.html"]{(chibi loop) - Fast and extensible loop syntax}}
|
|
|
|
\item{\hyperlink["lib/chibi/match.html"]{(chibi match) - Intuitive and widely supported pattern matching syntax}}
|
|
|
|
\item{\hyperlink["lib/chibi/mime.html"]{(chibi mime) - Parse MIME files into SXML}}
|
|
|
|
\item{\hyperlink["lib/chibi/modules.html"]{(chibi modules) - Introspection for the module system itself}}
|
|
|
|
\item{\hyperlink["lib/chibi/net.html"]{(chibi net) - Simple networking interface}}
|
|
|
|
\item{\hyperlink["lib/chibi/pathname.html"]{(chibi pathname) - Utilities to decompose and manipulate pathnames}}
|
|
|
|
\item{\hyperlink["lib/chibi/process.html"]{(chibi process) - Interface to spawn processes and handle signals}}
|
|
|
|
\item{\hyperlink["lib/chibi/repl.html"]{(chibi repl) - A full-featured Read/Eval/Print Loop}}
|
|
|
|
\item{\hyperlink["lib/chibi/scribble.html"]{(chibi scribble) - A parser for the scribble syntax used to write this manual}}
|
|
|
|
\item{\hyperlink["lib/chibi/show.html"]{(chibi show) - A combinator formatting library}}
|
|
|
|
\item{\hyperlink["lib/chibi/show/base.scm"]{(chibi show base) - Base combinator formatting}}
|
|
|
|
\item{\hyperlink["lib/chibi/stty.html"]{(chibi stty) - A high-level interface to ioctl}}
|
|
|
|
\item{\hyperlink["lib/chibi/system.html"]{(chibi system) - Access to the host system and current user information}}
|
|
|
|
\item{\hyperlink["lib/chibi/test.html"]{(chibi test) - A simple unit testing framework}}
|
|
|
|
\item{\hyperlink["lib/chibi/time.html"]{(chibi time) - An interface to the current system time}}
|
|
|
|
\item{\hyperlink["lib/chibi/trace.html"]{(chibi trace) - A utility to trace procedure calls}}
|
|
|
|
\item{\hyperlink["lib/chibi/type-inference.html"]{(chibi type-inference) - An easy-to-use type inference system}}
|
|
|
|
\item{\hyperlink["lib/chibi/uri.html"]{(chibi uri) - Utilities to parse and construct URIs}}
|
|
|
|
\item{\hyperlink["lib/chibi/weak.html"]{(chibi weak) - Data structures with weak references}}
|
|
|
|
]
|
|
|
|
\section{Snow Package Manager}
|
|
|
|
Beyond the distributed modules, Chibi comes with a package manager
|
|
based on \hyperlink["http://trac.sacrideo.us/wg/wiki/Snow"]{Snow2}
|
|
which can be used to share R7RS libraries. Packages are distributed
|
|
as tar gzipped files called "snowballs," and may contain multiple
|
|
libraries. The program is installed as \scheme{snow-chibi} and takes
|
|
the following subcommands:
|
|
|
|
\subsubsection{Querying Packages}
|
|
|
|
\itemlist[
|
|
|
|
\item{search terms ... - search for packages
|
|
\p{Prints a list of available packages matching the given keywords.}}
|
|
|
|
\item{show names ... - show package descriptions
|
|
\p{Show detailed information for the listed packages, which can
|
|
be sexp library names or the dotted shorthand used by chibi.}}
|
|
|
|
\item{status names ... - print package status
|
|
\p{Print the installed version of the given packages.}}
|
|
|
|
]
|
|
|
|
\subsubsection{Managing Packages}
|
|
|
|
\itemlist[
|
|
|
|
\item{install names ... - install packages
|
|
\p{Install the given packages.}}
|
|
|
|
\item{upgrade names ... - upgrade installed packages
|
|
\p{Upgrade the packages if new versions are available.
|
|
If no names are given, upgrades all eligible packages.}}
|
|
|
|
\item{remove names ... - remove packages
|
|
\p{Uninstalls the given packages.}}
|
|
|
|
]
|
|
|
|
\subsubsection{Creating Packages}
|
|
|
|
\itemlist[
|
|
|
|
\item{package files ... - create a package
|
|
\p{Create a package snowball from the given files, which should
|
|
be R7RS library files containing \scheme{define-library} forms.
|
|
Include files are inferred and packaged automatically.}}
|
|
|
|
\item{gen-key - create an RSA key pair
|
|
\p{Create a new private key pair.}}
|
|
|
|
\item{sign file - sign a package
|
|
\p{Sign a file with your private key and write it to the .sig file.}}
|
|
|
|
\item{verify file - verify a signature
|
|
\p{Print a message verifying if a signature is valid.}}
|
|
|
|
\item{reg-key - register an RSA key pair
|
|
\p{Register your key on the default snow host.}}
|
|
|
|
\item{upload files ... - upload a package
|
|
\p{Sign and upload to the default snow host.
|
|
A private key must be generated first.}}
|
|
|
|
]
|