#!r6rs
, #!r7rs
or
#!compatible
. For more details, see
Predefined reader macros.
-r6
option to run the script strict R6RS mode.
Multiple import of the same identifier is allowed. The value which
imported at the last will be used.sagittarius
on Unix like environment and sash
on Windows environment.
-r
option with Scheme standard number, currently 6
and 7
are supported, forces to run Sagittarius on strict standard
mode. For example, entire script is read then evaluated on R6RS
(-r6
option) mode. Thus macros can be located below the main script.
Detail options are given with option "-h"
.sash
is also provided
on Unix like environment. However this may not exist if Sagittarius is built
with disabling symbolic link option.
sagittarius
, it bounds an internal
variable to list of the remaining command-line arguments which you can get with
the command-line
procedure, then loads the Scheme program. If the first
line of scheme-file begins with "#!"
, then Sagittarius ignores the
entire line. This is useful to write a Scheme program that works as an
executable script in unix-like systems.
Typical Sagittarius script has the first line like this:
#!/usr/local/bin/sagittariusor
#!/bin/env sagittariusThe second form uses "shell trampoline" technique so that the script works as far as
sagittarius
is in the PATH.
After the script file is successfully loaded, then Sagittarius will process all
toplevel expression the same as Perl.
Now I show a simple example below. This script works like cat(1)
, without
any command-line option processing and error handling.
#!/usr/local/bin/sagittarius (import (rnrs)) (let ((args (command-line))) (unless (null? (cdr args)) (for-each (lambda (file) (call-with-input-file file (lambda (in) (display (get-string-all in))))) (cdr args))) 0)If the script file contains
main
procedure, then Sagittarius execute
it as well with one argument which contains all command line arguments. This
feature is defined in
SRFI-22. So the
above example can also be written like the following:
#!/usr/local/bin/sagittarius (import (rnrs)) (define (main args) (unless (null? (cdr args)) (for-each (lambda (file) (call-with-input-file file (lambda (in) (display (get-string-all in))))) (cdr args))) 0)NOTE: the
main
procedure is called after all toplevel expressions
are executed.
sagittarius
does not get any script file to process, then it will
go in to REPL (read-eval-print-loop). For developers' convenience, REPL
imports some libraries by default such as (rnrs)
.
If .sashrc
file is located in the directory indicated HOME
or
USERPROFILE
environment variable, then REPL reads it before evaluating
user input. So developer can pre-load some more libraries, instead of typing
each time.
NOTE: .sashrc
is only for REPL, it is developers duty to load all
libraries on script file.
library
syntax please see the R6RS document described in bellow sections.
(library (foo) (export bar) (import (rnrs)) (define bar 'bar) )The library named
(foo)
must be saved the file
named foo.scm
, foo.ss
, foo.sls
or foo.sld
(I use
.scm
for all examples) and located on the loading path, the value is
returned by calling add-load-path
with 0 length string.
If you want to write portable code yet want to use Sagittarius specific
functionality, then you can write implementation specific code separately using
.sagittarius.scm
, .sagittarius.ss
, .sagittarius.sls
or
.sagittarius.sld
extensions. This functionality is implemented almost
all R6RS implementation. If you use R7RS style library syntax, then you can
also use cond-expand
to separate implementation specific
functionalities.
If you don't want to share a library but only used in specific one, you can
write both in one file and name the file you want to show. For example;
(library (not showing) ;; exports all internal use procedures (export ...) (import (rnrs)) ;; write procedures ... ) (library (shared) (export shared-procedure ...) (import (rnrs) (not showing)) ;; write shared procedures here )Above script must be saved the file named
shared.scm
. The order of
libraries are important. Top most dependency must be the first and next is
second most, so on.
Note: This style can hide some private procedures however if you want to write
portable code, some implementations do not allow you to write this style.
SAGITTARIUS_CACHE_DIR
HOME
SAGITTARIUS_CACHE_DIR
TEMP
TMP
SAGITTARIUS_CACHE_DIR
is found then it will be used.
The caching compiled file is carefully designed however the cache file might be
stored in broken state. In that case use -c
option with
sagittarius
, then it will wipe all cache files. If you don't want to use
it, pass -d
option then Sagittarius won't use it.
(import (the-library-1) (the-library-2))When this script is run, then the libraries will be cached in the cache directory. Note: The cache files are stored with the names converted from original library files' absolute path. So it is important that users' libraries are already installed before precompiling, otherwise Sagittarius won't use the precompiled cache files.
"user"
. Here I list up all R6RS libraries. Some libraries contain
the same procedure ie. assoc which is in (rnrs (6))
and
(srfi :1 lists)
. In this case I will put a pointer to other library's
section.
If library specifies its version, Sagittarius, however, ignores it. This
behaviour may change in future.
import
clauses of all other libraries. It must have the following form:
(identifier1 identifier2 ... version)where version is empty or has the following form:
(sub-version ...)
An export-clause names a set of imported and locally defined bindings to
be exported. It must have following form:
(export export-spec ...)export-spec must have one of the following forms:
identifier
(rename (identifier1 identifier2) ...)
rename
spec
exports the binding named by identifier1 in each
(identifier1 identifier2)
pairing, using identifier2 as
the external name.
import-clause specifies a set of bindings to be imported into the
library. It must have the following form:
(import import-spec ...)Each import-spec specifies a set of bindings to be imported into the library. An import-spec must be one of the following:
(for import-set import-level ...)
run
expand
(meta level)
(library reference)
(only import-set identifier ...)
(except import-set identifier ...)
(prefix import-set identifier)
(rename import-set (identifier1 identifier2) ...)
(identifier1 identifier2 ...)
(identifier1 identifier2 ... version)
for, library, only, except, prefix
or rename
is permitted only
within a library
import-set. The import-set
(library reference)
is otherwise equivalent to reference.
By default, all of an imported library's exported bindings are made visible
within an importing library using the names given to the bindings by the
imported library. The precise set of bindings to be imported and the names of
those bindings can be adjusted with the only, except, prefix
and
rename
forms described below.
only
form produces a subset of the bindings from another
import-set, including only the listed identifiers. The included
identifiers should be in the original import-set.
except
form produces a subset of the bindings from another
import-set, including all but the listed identifiers. All of the
excluded identifiers should be in the original import-set.
prefix
form adds the identifier prefix to each name from
another import-set.
rename
form (rename identifier1 identifier2 ...)
,
removes the bindings for identifier1 ... to form an intermediate
import-set, then adds the bindings back for the corresponding
identifier2 ... to form the final import-set. Each
identifier1 should be the original import-set, each
identifier2 should not be int the intermediate import-set, and
the identifier2's must be distinct.
(library (foo) (export bar) (import (rename (rnrs) (define def) (not-exist define) (define def))) (def bar) )
(rnrs (6))
is required by R6RS. It just export
all symbols from the libraries which are listed below.define
form is a definition used to create variable
bindings and may appear anywhere other definitions may appear.
The first from of define
binds variable to a new location before
assigning the value of expression to it.
(define add3 (lambda (x) (+ x 3)))
(add3 3)=> 6
(define first car)
(first '(1 2))=> 1
define
is equivalent to
(define variable unspecified)where unspecified is a side-effect-free expression returning an unspecified value. In the third form of
define
, formals must be either a sequence of
zero or more variables, or a sequence of one or more variables followed by a dot
.
and another variable. This form is equivalent to
(define variable (lambda (formals) body ...))In the fourth form of
define
, formal must be a single variable.
This form is equivalent to
(define variable (lambda formal body ...))
define-syntax
form is a definition used to create keyword
bindings and may appear anywhere other definitions may appear.
Binds keyword to the value of expression, which must evaluate,
at macro-expansion time, to a transformer.
quote
evaluates to the datum value represented by datum.
(quote a)=> a
(quote #(a b c))=> #(a b c)
(quote (+ 1 2))=> (+ 1 2)
lambda
expression evaluates to a procedure. The
environment in effect when the lambda expression is evaluated is remembered as
part of the procedure. When the procedure is later called with some arguments,
the environment in which the lambda
expression was evaluated is extended
by binding the variables in the parameter list to fresh locations, and the
resulting argument values are stored in those locations. Then, the expressions
in the body of the lambda
expression are evaluated sequentially in
the extended environment. The results of the last expression in the body are
returned as the results of the procedure call.
(lambda (x) (+ x x))=> a procedure
((lambda (x) (+ x x)) 4)=> 8
=> 11((lambda (x) (define (p y) (+ y 1)) (+ (p x) x)) 5)
(define reverse-subtract (lambda (x y) (- y x)))
(reverse-subtract 7 10)=> 3
(define add4 (let ((x 4)) (lambda (y) (+ x y))))
(add4 6)=> 10
The procedure takes a fixed number of arguments; when the procedure is called, the arguments are stored in the bindings of the corresponding variables.
The procedure takes any number of arguments; when the procedure is called, the sequence of arguments is converted into a newly allocated list, and the list is stored in the binding of the <variable>.
If a period .
precedes the last variable, then the procedure takes
n or more arguments, where n is the number of parameters before
the period (there must be at least one). The value stored in the binding of
the last variable is a newly allocated list of the arguments left over after
all the other arguments have been matched up against the other
parameters.
((lambda x x) 3 4 5 6)=> (3 4 5 6)
((lambda (x y . z) z) 3 4 5 6)=> (5 6)
:optional
, :key
or :rest
.
The <extended-spec> part consists of the optional argument spec, the
keyword argument spec and the rest argument spec. They can appear in any
combinations.
:optional optspec ...
variable
(variable init-expr)The variable names the formal argument, which is bound to the value of the actual argument if given, or the value of the expression init-expr otherwise. If optspec is just a variable, and the actual argument is not given, then it will be unspecified value. The expression init-expr is only evaluated if the actual argument is not given. The scope in which init-expr is evaluated includes the preceding formal arguments.
((lambda (a b :optional (c (+ a b))) (list a b c)) 1 2)=> (1 2 3)
((lambda (a b :optional (c (+ a b))) (list a b c)) 1 2 -1)=> (1 2 -1)
((lambda (a b :optional c) (list a b c)) 1 2)=> (1 2 #<unspecified>)
((lambda (:optional (a 0) (b (+ a 1))) (list a b)))=> (1 2)
&serious
if more actual arguments than the
number of required and optional arguments are given, unless it also has
:key
or :rest
arguments spec.
((lambda (:optional a b) (list a b)) 1 2 3)=> &serious
((lambda (:optional a b :rest r) (list a b r)) 1 2 3)=> (1 2 (3))
:key keyspec ... [:allow-other-keys [variable]]
variable
(variable init-expr)
((keyword variable) init-expr)
(variable keyword init-expr)The variable names the formal argument, which is bound to the actual argument given with the keyword of the same name as variable. When the actual is not given, init-expr is evaluated and the result is bound to variable in the second, third and fourth form, or unspecified value is bound in the first form.
(define f (lambda (a :key (b (+ a 1)) (c (+ b 1))) (list a b c)))
(f 10)=> (10 11 12)
(f 10 :b 4)=> (10 4 5)
(f 10 :c 8)=> (10 11 8)
(f 10 :c 1 :b 3)=> (10 3 1)
((lambda (:key ((:aa a) -1)) a) ::aa 2)=> 2
((lambda (:key (a :aa -1)) a) ::aa 2)=> 2
&serious
if a keyword argument with an unrecognized keyword is
given. Giving :allow-other-keys
in the formals suppresses this
behaviour. If you give variable after :allow-other-keys
, the
list of unrecognized keywords and their arguments are bound to it.
((lambda (:key a) a) :a 1 :b 2)=> &serious
((lambda (:key a :allow-other-keys) a) :a 1 :b 2)=> 1
((lambda (:key a :allow-other-keys z) (list a z)) :a 1 :b 2)=> (1 (b 2))
:optional
argument spec, the keyword arguments are
searched after all the optional arguments are bound.
((lambda (:optional a b :key c) (list a b c)) 1 2 :c 3)=> (1 2 3)
((lambda (:optional a b :key c) (list a b c)) :c 3)=> (c 3 #<unspecified>)
((lambda (:optional a b :key c) (list a b c)) 1 :c 3)=> &serious
:rest variable
:optional
argument spec, a list of remaining arguments after required arguments are
taken is bound to variable. If specified with :optional
argument spec, the actual arguments are first bound to required and all
optional arguments, and the remaining arguments are bound to
variable.
((lambda (a b :rest z) (list a b z)) 1 2 3 4 5)=> (1 2 (3 4 5))
((lambda (a b :optional c d :rest z) (list a b z)) 1 2 3 4 5)=> (1 2 3 4 (5))
((lambda (a b :optional c d :rest z) (list a b z)) 1 2 3)=> (1 2 3 #<unspecified> ())
((lambda (:optional a :rest r :key k) (list a r k)) 1 :k 3)=> (1 (k 3) 3)
if
expression is evaluated as follows: first, test
is evaluated. If it yields a true value, then consequent is evaluated and
its values are returned. Otherwise alternate is evaluated and its values
are returned. If test yields #f and no alternate is specified, then
the result of the expression is unspecified.
set!
expression or at the top level. The result
of the set!
expression is unspecified.
Note: R6RS requires to throw syntax violation if variable refers immutable
binding. In Sagittarius, however, it won't throw any error.
(test expression ...)
(test => expression)
(else expression ...)The last form can appear only in the last clause. A
cond
expression is evaluated by evaluating the test expressions of
successive clauses in order until one of them evaluates to a true value.
When a test evaluates to a true value, then the remaining expressions in
its clause are evaluated in order, and the results of the last expression
in the clause are returned as the results of the entire cond
expression.
If the selected clause contains only the test and no expressions,
then the value of the test is returned as the result. If the selected
clause uses the =>
alternate form, then the expression is evaluated.
Its value must be a procedure. This procedure should accept one argument; it is
called on the value of the test and the values returned by this procedure
are returned by the cond
expression. If all tests evaluate to #f,
and there is no else
clause, then the conditional expression returns
unspecified values; if there is an else
clause, then its expressions are
evaluated, and the values of the last one are returned.
((datum ...) expression ...)
(else expression ...)The last form can appear only in the last clause. A
case
expression is evaluated as follows. Key is evaluated and its
result is compared using eqv?
against the data represented by the datums
of each clause in turn, proceeding in order from left to right through
the set of clauses. If the result of evaluating key is equivalent to a datum
of a clause, the corresponding expressions are evaluated from left to right
and the results of the last expression in the clause are returned as the
results of the case
expression. Otherwise, the comparison process continues.
If the result of evaluating key is different from every datum in each set,
then if there is an else
clause its expressions are evaluated and the
results of the last are the results of the case
expression; otherwise the
case
expression returns unspecified values.
(and (= 2 2) (> 2 1))=> #t
(and (= 2 2) (< 2 1))=> #f
(and 1 2 'c '(f g))=> (f g)
(and)=> #t
(or (= 2 2) (> 2 1))=> #t
(or (= 2 2) (< 2 1))=> #t
(or #f #f #f)=> #f
(or '(b c) (/ 3 0))=> (b c)
((variable1 init1) ...)where each init is an expression. Any variable must not appear more than once in the variables. The inits are evaluated in the current environment, the variables are bound to fresh locations holding the results, the body is evaluated in the extended environment, and the values of the last expression of body are returned. Each binding of a variable has body as its region.
((variable1 init1) ...)The
let*
form is similar to let
, but the inits are evaluated
and bindings created sequentially from left to right, with the region of each
binding including the bindings to its right as well as body. Thus the second
init is evaluated in an environment in which the first binding is visible
and initialized, and so on.
((variable1 init1) ...)where each init is an expression. Any variable must not appear more than once in the variables. The variables are bound to fresh locations, the inits are evaluated in the resulting environment, each variable is assigned to the result of the corresponding init, the body is evaluated in the resulting environment, and the values of the last expression in body are returned. Each binding of a variable has the entire
letrec
expression as its region, making it
possible to define mutually recursive procedures.
In the most common uses of letrec
, all the inits are lambda
expressions and the restriction is satisfied automatically.
((variable1 init1) ...)where each init is an expression. Any variable must not appear more than once in the variables. The variables are bound to fresh locations, each variable is assigned in left-to-right order to the result of evaluating the corresponding init, the body is evaluated in the resulting environment, and the values of the last expression in body are returned. Despite the left-to-right evaluation and assignment order, each binding of a variable has the entire
letrec*
expression as its region, making it possible to define mutually recursive procedures.
((formals init1) ...)where each init is an expression. Any variable must not appear more than once in the set of formals. The inits are evaluated in the current environment, and the variables occurring in the formals are bound to fresh locations containing the values returned by the inits, where the formals are matched to the return values in the same way that the formals in a
lambda
expression are
matched to the arguments in a procedure call. Then, the body is evaluated
in the extended environment, and the values of the last expression of body
are returned. Each binding of a variable has body as its region. If the
formals do not match, an exception with condition type &assertion
is raised.
((formals init1) ...)where each init is an expression. In each formals, any variable must not appear more than once. The
let*-values
form is similar to let-values
, but the inits
are evaluated and bindings created sequentially from left to right, with the
region of the bindings of each formals including the bindings to its right
as well as body. Thus the second init is evaluated in an environment
in which the bindings of the first formals is visible and initialized, and
so on.
predicate
is a procedure that always returns a boolean value (#t or #f).
An equivalence predicate
is the computational analogue of a mathematical
equivalence relation (it is symmetric, reflexive, and transitive). Of the
equivalence predicates described in this section, eq?
is the finest or
most discriminating, and equal?
is the coarsest. The eqv?
predicate
is slightly less discriminating than eq?
.
eq?
only sees if the given two objects are the same object
or not, eqv?
compares numbers. equal?
compares the values
equivalence.
On Sagittarius Scheme interned symbol, keyword(only compatible mode), character,
literal string, boolean, fixnum, and '() are used as the same objects. If these
objects indicates the same value then eq?
returns #t.
The following examples are not specified R6RS. But it is always good to know how
it works.
(let ((p (lambda (x) x))) (eqv? p p))=> #t
(eqv? "" "")=> #t
(eqv? "abc" "abc") ;; literal string are the same object=> #t
(eqv? "abc" (list->string '(#\a #\b #\c)))=> #f
(eqv? '#() '#())=> #f
(eqv? (lambda (x) x) (lambda (x) x))=> #f
(eqv? (lambda (x) x) (lambda (y) y))=> #f
(eqv? +nan.0 +nan.0)=> #f
(real? z)
is true if and
only if (zero? (imag-part z))
and (exact? (imag-part z))
are both true.
If x is a real number object, then (rational? x)
is true if
and only if there exist exact integer objects k1 and k2 such that
(= x (/ k1 k2))
and (= (numerator x) k1)
and (= (denominator x) k2)
are all true. Thus infinities and
NaNs are not rational number objects.
If q is a rational number objects, then (integer? q)
is true
if and only if (= (denominator q) 1)
is true. If q is not a rational
number object, then (integer? q)
is #f.
real-valued?
procedure returns #t if the object is a number object and
is equal in the sense of =
to some real number object, or if the object is
a NaN, or a complex number object whose real part is a NaN and whose imaginary part
is zero in the sense of zero?. The rational-valued?
and integer-valued?
procedures return #t if the object is a number object and is equal in the sense
of =
to some object of the named type, and otherwise they return #f.
inexact
procedure returns an inexact representation of
z. If inexact number objects of the appropriate type have bounded precision,
then the value returned is an inexact number object that is nearest to the argument.
The exact
procedure returns an exact representation of z. The value
returned is the exact number object that is numerically closest to the argument;
in most cases, the result of this procedure should be numerically equal to its argument.
zero?
procedure tests if the number object is =
to zero.
The positive?
tests whether it is greater than zero.
The negative?
tests whether it is less than zero.
The odd?
tests whether it is odd.
The even?
tests whether it is even
The finite?
tests whether it is not an infinity and not a NaN.
The infinite?
tests whether it is an infinity.
The nan?
tests whether it is a NaN.
&assertion
when the divisor was 0, on
Sagittarius, however, it returns NaN or infinite number when it is running with
compatible mode. In R6RS mode it raises &assertion
.
&assertion
is raised.
floor
returns the largest integer object
not larger than x. The ceiling
procedure returns the smallest
integer object not smaller than x. The truncate
procedure returns
the integer object closest to x whose absolute value is not larger than
the absolute value of x. The round
procedure returns the closest
integer object to x, rounding to even when x represents a number
halfway between two integers.
Although infinities and NaNs are not integer objects, these procedures return
an infinity when given an infinity as an argument, and a NaN when given a NaN.
rationalize
procedure returns the a number object
representing the simplest rational number differing from x1 by no more than
x2. A rational number r1 is simpler than another rational number
r2 if r1 = p1/q1 and r2 = p2/q2 (in
lowest terms) and |p1| ≤ |p2| and |q1| ≤ |q2|. Thus 3/5
is simpler than 4/7. Although not all rationals are comparable in this ordering
(consider 2/7 and 3/5) any interval contains a rational number that is simpler
than every other rational number in that interval (the simpler 2/5 lies between
2/7 and 3/5). Note that 0 = 0/1 is the simplest rational of all.
exp
procedure computes the base-e exponential of z.
The log
procedure with a single argument computes the natural logarithm
of z (not the base-ten logarithm); (log z1 z2)
computes
the base-z2 logarithm of z1.
The asin
, acos
, and atan
procedures compute arcsine,
arccosine, and arctangent, respectively.
The two-argument variant of atan
computes
(angle (make-rectangular x2 x1))
.
(real-part z)
is
positive. For other cases in which the first argument is zero, an unspecified
number object(+nan.0+nan.0i
) is returned.
For an exact real number object z1 and an exact integer object z2,
(expt z1 z2)
must return an exact result. For all other values
of z1 and z2, (expt z1 z2)
may return an inexact
result, even when both z1 and z2 are exact.
(make-rectangular x1 x2)
returns c, and
(make-polar x3 x4)
returns c.
number->string
procedure takes a number object and a radix
and returns as a string an external representation of the given number object in
the given radix such that
(let ((number z) (radix radix)) (eqv? (string->number (number->string number radix) radix) number))is true.
string->number
returns #f.
These number->string
and string->number
's resolutions of radix are
taken from Gauche.
cons
. The car
and cdr fields are accessed by the procedures car
and cdr
.
Pairs are used primarily to represent lists. A list can be defined recursively as
either the empty list or a pair whose cdr is a list. More precisely, the set of
lists is defined as the smallest set X such that
(a b c . d)is equivalent to
(a . (b . (c . d)))Whether a given pair is a list depends upon what is stored in the cdr field.
eqv?
) from every existing object.
car
and cdr
,
where for example caddr
could be defined by
(define caddr (lambda (x) (car (cdr (cdr x))))). Arbitrary compositions, up to four deep, are provided. There are twenty-eight of these procedures in all.
list-tail
procedure returns the subchain of pairs of
list obtained by omitting the first k elements. If fallback
is given and k is out of range, it returns fallback otherwise
&assertion
is raised.
list-ref
procedure returns the kth element of
list. If fallback is given and k is out of range, it returns
fallback otherwise &assertion
is raised.
map
procedure applies proc element-wise to
the elements of the lists and returns a list of the results, in order. The
order in which proc is applied to the elements of the lists is unspecified.
If multiple returns occur from map
, the values returned by earlier returns
are not mutated. If the given lists are not the same length, when the
shortest list is processed the map
will stop.
for-each
procedure applies proc element-wise
to the elements of the lists for its side effects, in order from the first
elements to the last. The return values of for-each
are unspecified. If
the given lists are not the same length, when the shortest list is
processed the for-each
will stop.
char->integer
returns its Unicode scalar value as an
exact integer object. For a Unicode scalar value sv, integer->char
returns its associated character.
#\space
.
These are equivalence:
(make-string 10)=> (code (make-string 10 #\space))
string-ref
procedure returns character. If a third
argument is given ant k is not a valid index, it returns fallback,
otherwise raises &assertion
.
k of string using zero-origin indexing.
string=?
procedure
returns #f.
string<?
is the
lexicographic ordering on strings induced by the ordering char<?
on
characters. If two strings differ in length but are the same up to the length of
the shorter string, the shorter string is considered to be lexicographically less
than the longer string.
(string-length string)
.
The substring
procedure returns a newly allocated string formed from the
characters of string beginning with index start (inclusive) and ending with
index end (exclusive).
string->list
procedure returns a newly allocated list of the
characters that make up the given string.
The list->string
procedure returns a newly allocated string formed from
the characters in list.
The string->list
and list->string
procedures are inverses so far
as equal?
is concerned.
If optional argument start and end are given, it restrict the
conversion range. It convert from start (inclusive) to end
(exclusive).
If only start is given, then the end is the length of given string.
string-for-each
procedure applies proc element-wise to the
characters of the strings for its side effects, in order from the first
characters to the last. The return values of string-for-each
are unspecified.
Analogous to for-each.
list
.vector-ref
procedure returns the contents of element
k of vector. If a third argument is given and k is not a valid
index, it returns fallback, otherwise raises &assertion
.
vector-set!
procedure stores obj in element k of vector, and returns
unspecified values.
It raises &assertion
when it attempt to modify immutable vector on R6RS
mode.
vector->list
procedure returns a newly allocated list
of the objects contained in the elements of vector. The list->vector
procedure returns a newly created vector initialized to the elements of the list
list. The optional start and end arguments limit the range of
the source.
(vector->list '#(1 2 3 4 5))=> (1 2 3 4 5)
(list->vector '(1 2 3 4 5))=> #(1 2 3 4 5)
(vector->list '#(1 2 3 4 5) 2 4)=> (3 4)
(list->vector (circular-list 'a 'b 'c) 1 6)=> #(b c a b c)
vector-map
procedure applies proc element-wise to the elements
of the vectors and returns a vector of the results, in order. If multiple
returns occur from vector-map
, the return values returned by earlier
returns are not mutated.
Analogous to map
.
vector-for-each
procedure applies proc element-wise to the
elements of the vectors for its side effects, in order from the first
elements to the last. The return values of vector-for-each
are unspecified.
Analogous to for-each
.
error
procedure should be called
when an error has occurred, typically caused by something that has gone wrong in
the interaction of the program with the external world or the user. The
assertion-violation
procedure should be called when an invalid call to a
procedure was made, either passing an invalid number of arguments, or passing an
argument that it is not specified to handle.
The who argument should describe the procedure or operation that detected
the exception. The message argument should describe the exceptional situation.
The irritants should be the arguments to the operation that detected the
operation.
apply
procedure calls proc with the elements of the list
(append (list arg1 ...) rest-args)
as the actual arguments.
If a call to apply
occurs in a tail context, the call to proc
is
also in a tail context.
call-with-current-continuation
(which is the same as the procedure
call/cc
) packages the current continuation as an "escape procedure" and
passes it as an argument to proc. The escape procedure is a Scheme procedure
that, if it is later called, will abandon whatever continuation is in effect a
that later time and will instead reinstate the continuation that was in effect
when the escape procedure was created. Calling the escape procedure may cause
the invocation of before and after procedures installed using
dynamic-wind
.
The escape procedure accepts the same number of arguments as the continuation
of the original call to call-with-current-continuation
.
call-with-values
procedure calls producer
with no arguments and a continuation that, when passed some values, calls the
consumer procedure with those values as arguments. The continuation for
the call to consumer is the continuation of the call to call-with-values
.
If a call to call-with-values
occurs in a tail context, the call to
consumer is also in a tail context.
dynamic-wind
procedure calls thunk without arguments,
returning the results of this call. Moreover, dynamic-wind
calls before
without arguments whenever the dynamic extent of the call to thunk is
entered, and after without arguments whenever the dynamic extent of the
call to thunk is exited. Thus, in the absence of calls to escape procedures
created by call-with-current-continuation
, dynamic-wind
calls
before, thunk, and after, in that order.
let
that provides
a general looping construct and may also be used to express recursion. It has
the same syntax and semantics as ordinary let
except that variable
is bound within body to a procedure whose parameters are the bound variables
and whose body is body. Thus the execution of body may be repeated
by invoking the procedure named by variable.
unquote
or unquote-splicing
forms appear within the
qq-template, the result of evaluating (quasiquote qq-template)
is equivalent to the result of evaluating (quote qq-template)
.
If an (unquote expression ...)
form appears inside a qq-template,
however, the expressions are evaluated ("unquoted")
and their results are
inserted into the structure instead of the unquote
form.
If an (unquote-splicing expression ...)
form appears inside a
qq-template, then the expressions must evaluate to lists; the opening and
closing parentheses of the lists are then "stripped away" and the elements of
the lists are inserted in place of the unquote-splicing
form.
Any unquote-splicing
or multi-operand unquote form must appear only within
a list or vector qq-template.
Note: even though unquote
and unquote-splicing
are bounded, however
it does not work with import prefix nor renamed import. This may be fixed in future.
let-syntax
and letrec-syntax
forms bind keywords. On R6RS mode
it works like a begin
form, a let-syntax
or letrec-syntax
form may appear in a definition context, in which case it is treated as a
definition, and the forms in the body must also be definitions. A let-syntax
or letrec-syntax
form may also appear in an expression context, in which
case the forms within their bodies must be expressions.
((keyword expression) ...)Each keyword is an identifier, and each expression is an expression that evaluates, at macro-expansion time, to a transformer. Transformers may be created by
syntax-rules
or identifier-syntax
or by one of the other
mechanisms described in library chapter on "syntax-case".
It is a syntax violation for keyword to appear more than once in the list
of keywords being bound.
The forms are expanded in the syntactic environment obtained by extending
the syntactic environment of the let-syntax
form with macros whose keywords
are the keywords, bound to the specified transformers. Each binding of a
keyword has the forms as its region.
((keyword expression) ...)Each keyword is an identifier, and each expression is an expression that evaluates, at macro-expansion time, to a transformer. Transformers may be created by
syntax-rules
or identifier-syntax
or by one of the other
mechanisms described in library chapter on "syntax-case".
It is a syntax violation for keyword to appear more than once in the list
of keywords being bound.
The forms are expanded in the syntactic environment obtained by extending
the syntactic environment of the letrec-syntax
form with macros whose
keywords are the keywords, bound to the specified transformers. Each
binding of a keyword has the bindings as well as the forms within its
region, so the transformers can transcribe forms into uses of the macros
introduced by the letrec-syntax
form.
Note: The forms of a let-syntax
and a letrec-syntax
form are
treated, whether in definition or expression context, as if wrapped in an implicit
begin
on R6RS mode, it is, then, treated as if wrapped in an implicit
let
on compatible mode. Thus on compatible mode, it creates a scope.
'_'
'...'
as bounded symbols but in Sagittarius
these are not bound. And if import clause has rename or prefix these auxiliary
syntax are not be renamed or prefixed. This behaivour may be fixed in future.
(srpattern template)An srpattern is a restricted form of pattern, namely, a nonempty pattern in one of four parenthesized forms below whose first subform is an identifier or an underscore
_
. A pattern is an identifier,
constant, or one of the following.
"..."
(three periods).
A template is a pattern variable, an identifier that is not a pattern
variable, a pattern datum, or one of the following.
syntax-rules
evaluates, at macro-expansion time, to a new
macro transformer by specifying a sequence of hygienic rewrite rules. A use of a
macro whose keyword is associated with a transformer specified by syntax-rules
is matched against the patterns contained in the rules, beginning with the
leftmost rule. When a match is found, the macro use is transcribed hygienically
according to the template. It is a syntax violation when no match is found.
syntax-rules
.
When a keyword is bound to a transformer produced by the first form of
identifier-syntax
, references to the keyword within the scope of the
binding are replaced by template.
(define p (cons 4 5))
(define-syntax p.car (identifier-syntax (car p)))
p.car=> 4
(set! p.car 15)=> &syntax exception
identifier-syntax
permits the transformer
to determine what happens when set!
is used. In this case, uses of the
identifier by itself are replaced by template1, and uses of set!
with
the identifier are replaced by template2
(define p (cons 4 5))
(define-syntax p.car (identifier-syntax (_ (car p)) ((set! _ e) (set-car! p e))))
(set! p.car 15)
p.car=> 15
p=> (15 5)
(rnrs unicode (6))
library
provide access to some aspects of the Unicode semantics for characters and strings:
category information, case-independent comparisons, case mappings, and normalization.
Some of the procedures that operate on characters or strings ignore the difference
between upper case and lower case. These procedures have "-ci"
(for "case insensitive") embedded in their names.
char-downcase
returns that character. If the argument is a lower-case or title-case character,
and there is a single character that is its upper-case form, then char-upcase
returns that character. If the argument is a lower-case or upper-case character,
and there is a single character that is its title-case form, then char-titlecase
returns that character. If the argument is not a title-case character and there
is no single character that is its title-case form, then char-titlecase
returns the upper-case form of the argument. Finally, if the character has a
case-folded character, then char-foldcase
returns that character. Otherwise
the character returned is the same as the argument. For Turkic characters İ (#\x130)
and ı (#\x131), char-foldcase
behaves as the identity function; otherwise
char-foldcase
is the same as char-downcase
composed with
char-upcase
.
char=?
, etc., but operate on
the case-folded versions of the characters.
string=?
to the argument, these procedures may return the argument
instead of a newly allocated string.
The string-upcase
procedure converts a string to upper case;
string-downcase
converts a string to lower case.
The string-foldcase
procedure converts the string to its case-folded
counterpart, using the full case-folding mapping, but without the special
mappings for Turkic languages.
The string-titlecase
procedure converts the first cased character of each
word via char-titlecase
, and downcases all other cased characters.
If the optional argument start and end are given, these must be
exact integer and the procedures will first substring the given string with
range start and end then convert it.
string=?
, etc., but operate
on the case-folded versions of the strings.
string=?
to the argument, these procedures may return the argument instead of a newly
allocated string.
(rnrs bytevectors (6))
library provides a single type for blocks of binary
data with multiple ways to access that data. It deals with integers and
floating-point representations in various sizes with specified endianness.
Bytevectorsare objects of a disjoint type. Conceptually, a bytevector represents
a sequence of 8-bit bytes. The description of bytevectors uses the term byte for
an exact integer object in the interval { - 128, ..., 127} and the term octet for
an exact integer object in the interval {0, ..., 255}. A byte corresponds to its
two's complement representation as an octet.
The length of a bytevector is the number of bytes it contains. This number is
fixed. A valid index into a bytevector is an exact, non-negative integer object
less than the length of the bytevector. The first byte of a bytevector has index
0; the last byte has an index one less than the length of the bytevector.
Generally, the access procedures come in different flavors according to the size
of the represented integer and the endianness of the representation. The procedures
also distinguish signed and unsigned representations. The signed representations
all use two's complement.
Like string literals, literals representing bytevectors do not need to be quoted:
#vu8(12 23 123)=> #vu8(12 23 123)
(endianness symbol)
evaluates to the symbol named symbol.
Whenever one of the procedures operating on bytevectors accepts an endianness as
an argument, that argument must be one of these symbols. It is a syntax violation
for symbol to be anything other than an endianness symbol supported by the Sagittarius.
Currently, Sagittarius supports these symbols; big
, little
and native
.
make-bytevector
procedure. The bytevector-fill!
procedure stores
fill in every element of bytevector and returns unspecified values.
Analogous to vector-fill!
.
If optional arguments start or end is given, then the procedure
restricts the range of filling from start to end (exclusive) index
of bytevector. When end is omitted then it uses the length of the
given bytevector.
bytevector-copy!
procedure copies the bytes from source at indices
source-start, ... source-start + k - 1
to consecutive indices in target starting at target-index.
This returns unspecified values.
bytevector-u8-ref
procedure returns the byte at index k of
bytevector, as an octet.
The bytevector-s8-ref
procedure returns the byte at index k of
bytevector, as a (signed) byte.
bytevector-u8-set!
procedure stores octet in element k
of bytevector.
The bytevector-s8-set!
procedure stores the two's-complement
representation of byte in element k of bytevector.
Both procedures return unspecified values.
bytevector->u8-list
procedure returns a newly allocated list of the
octets of bytevector in the same order.
The u8-list->bytevector
procedure returns a newly allocated bytevector
whose elements are the elements of list list, in the same order. It is
analogous to list->vector
.
bytevector-uint-ref
procedure retrieves the exact integer object
corresponding to the unsigned representation of size size and specified
by endianness at indices k, ..., k + size - 1.
The bytevector-sint-ref
procedure retrieves the exact integer object
corresponding to the two's-complement representation of size size and
specified by endianness at indices k, ..., k + size - 1.
For bytevector-uint-set!
, n must be an exact integer object in the
interval
The bytevector-uint-set!
procedure stores the unsigned representation of
size size and specified by endianness into bytevector at indices
k, ..., k + size - 1.
For bytevector-sint-set!
, n must be an exact integer object in the
interval .
bytevector-sint-set!
stores the two's-complement representation of size
size and specified by endianness into bytevector at indices
k, ..., k + size - 1.
The ...-set!
procedures return unspecified values.
uint-list->bytevector
, list must be a list of exact integer objects
in the interval . For sint-list->bytevector
,
list must be a list of exact integer objects in the interval
. The length of bytevector
or, respectively, of list must be divisible by size.
These procedures convert between lists of integer objects and their consecutive
representations according to size and endianness in the bytevector
objects in the same way as bytevector->u8-list
and u8-list->bytevector
do for one-byte representations.
bytevector-u16-set!
and bytevector-u16-native-set!
, n
must be an exact integer object in the interval .
For bytevector-s16-set!
and bytevector-s16-native-set!
, n
must be an exact integer object in the interval .
These retrieve and set two-byte representations of numbers at indices k
and k + 1, according to the endianness specified by endianness.
The procedures with u16
in their names deal with the unsigned representation;
those with s16
in their names deal with the two's-complement representation.
The procedures with native
in their names employ the native endianness,
and work only at aligned indices: k must be a multiple of 2.
The ...-set!
procedures return unspecified values.
bytevector-u32-set!
and bytevector-u32-native-set!
, n
must be an exact integer object in the interval .
For bytevector-s32-set!
and bytevector-s32-native-set!
, n
must be an exact integer object in the interval .
These retrieve and set two-byte representations of numbers at indices k
and k + 3, according to the endianness specified by endianness.
The procedures with u32
in their names deal with the unsigned representation;
those with s32
in their names deal with the two's-complement representation.
The procedures with native
in their names employ the native endianness,
and work only at aligned indices: k must be a multiple of 4.
The ...-set!
procedures return unspecified values.
bytevector-u64-set!
and bytevector-u64-native-set!
, n
must be an exact integer object in the interval .
For bytevector-s64-set!
and bytevector-s64-native-set!
, n
must be an exact integer object in the interval .
These retrieve and set two-byte representations of numbers at indices k
and k + 7, according to the endianness specified by endianness.
The procedures with u64
in their names deal with the unsigned representation;
those with s64
in their names deal with the two's-complement representation.
The procedures with native
in their names employ the native endianness,
and work only at aligned indices: k must be a multiple of 8.
The ...-set!
procedures return unspecified values.
bytevector-ieee-single-native-ref
, k must be a multiple of 4.
These procedures return the inexact real number object that best represents the
IEEE-754 single-precision number represented by the four bytes beginning at index
k.
bytevector-ieee-double-native-ref
, k must be a multiple of 8.
These procedures return the inexact real number object that best represents the
IEEE-754 double-precision number represented by the four bytes beginning at index
k.
bytevector-ieee-single-native-set!
, k must be a multiple of 4.
These procedures store an IEEE-754 single-precision representation of x
into elements k through k + 3 of bytevector, and return
unspecified values.
bytevector-ieee-double-native-set!
, k must be a multiple of 8.
These procedures store an IEEE-754 double-precision representation of x
into elements k through k + 7 of bytevector, and return
unspecified values.
big
or the symbol little
. The string->utf16
procedure returns a newly
allocated (unless empty) bytevector that contains the UTF-16BE or UTF-16LE
encoding of the given string (with no byte-order mark). If endianness
is not specified or is big
, then UTF-16BE is used. If endianness is
little
, then UTF-16LE is used.
big
or the symbol little
. The string->utf32
procedure returns a newly
allocated (unless empty) bytevector that contains the UTF-32BE or UTF-32LE
encoding of the given string (with no byte-order mark). If endianness
is not specified or is big
, then UTF-32BE is used. If endianness is
little
, then UTF-32LE is used.
big
or the symbol
little
. The utf16->string
procedure returns a newly allocated
(unless empty) string whose character sequence is encoded by the given
bytevector. Bytevector is decoded according to UTF-16BE or UTF-16LE:
If endianness-mandatory? is absent or #f, utf16->string
determines
the endianness according to a UTF-16 BOM at the beginning of bytevector
if a BOM is present; in this case, the BOM is not decoded as a character. Also
in this case, if no UTF-16 BOM is present, endianness specifies the endianness
of the encoding. If endianness-mandatory? is a true value, endianness
specifies the endianness of the encoding, and any UTF-16 BOM in the encoding is
decoded as a regular character.
big
or the symbol
little
. The utf32->string
procedure returns a newly allocated
(unless empty) string whose character sequence is encoded by the given
bytevector. Bytevector is decoded according to UTF-32BE or UTF-32LE:
If endianness-mandatory? is absent or #f, utf32->string
determines
the endianness according to a UTF-32 BOM at the beginning of bytevector
if a BOM is present; in this case, the BOM is not decoded as a character. Also
in this case, if no UTF-32 BOM is present, endianness specifies the endianness
of the encoding. If endianness-mandatory? is a true value, endianness
specifies the endianness of the encoding, and any UTF-32 BOM in the encoding is
decoded as a regular character.
(rnrs lists (6))
library, which contains various useful
procedures that operate on lists.
find
procedure applies proc
to the elements of list in order. If proc returns a true value for
an element, find immediately returns that element. If proc returns #f for
all elements of the list, find returns #f.
for-all
returns the last result of the applications.
for-all
and exists
.
On Sagittarius, however, these can accept different length list and it will
finish to process when the shortest list is finish to process.
filter
procedure applies proc to each element of list and
returns a list of the elements of list for which proc returned a true
value. The partition
procedure also applies proc to each element of
list, but returns two values, the first one a list of the elements of list
for which proc returned a true value, and the second a list of the elements
of list for which proc returned #f. In both cases, the elements of the
result list(s) are in the same order as they appear in the input list. If multiple
returns occur from filter
or partitions
, the return values returned
by earlier returns are not mutated.
fold-left
procedure iterates the combine
procedure over an accumulator value and the elements of the lists from left
to right, starting with an accumulator value of nil. More specifically,
fold-left
returns nil if the lists are empty. If they are not
empty, combine is first applied to nil and the respective first
elements of the lists in order. The result becomes the new accumulator
value, and combine is applied to the new accumulator value and the respective
next elements of the list. This step is repeated until the end of the
list is reached; then the accumulator value is returned.
fold-right
procedure iterates the
combine procedure over the elements of the lists from right to left
and an accumulator value, starting with an accumulator value of nil. More
specifically, fold-right
returns nil if the lists are empty. If they
are not empty, combine is first applied to the respective last elements of
the lists in order and nil. The result becomes the new accumulator
value, and combine is applied to the respective previous elements of the
lists and the new accumulator value. This step is repeated until the beginning
of the list is reached; then the accumulator value is returned.
Note: R6RS requires the same length list for fold-left
and fold-right
.
On Sagittarius, however, these can accept different length list and it will finish
to process when the shortest list is finish to process.
remp
procedure applies proc to each
element of list and returns a list of the elements of list for which
proc returned #f. The remove
, remq
procedures
return a list of the elements that are not obj. The remq
procedure
uses eq?
to compare obj with the elements of list, while
remv
uses eqv?
and remove
uses equal?
. The elements
of the result list are in the same order as they appear in the input list. If
multiple returns occur from remp
, the return values returned by earlier
returns are not mutated.
(list-tail list k)
for k less than the length of list.
The memp
procedure applies proc to the cars of the sublists of
list until it finds one for which proc returns a true value. The
member
, memv
, and memq
procedures look for the first
occurrence of obj. If list does not contain an element satisfying the
condition, then #f (not the empty list) is returned. The member
procedure
uses equal?
or if = is given use it to compare obj with the
elements of list, while memv
uses eqv?
and memq
uses
eq?
.
assp
procedure successively applies proc to the car fields of
alist and looks for a pair for which it returns a true value. The
assoc
, assv
, and assq
procedures look for a pair that has
obj as its car. The assoc
procedure uses equal?
or if =
is given use it to compare obj with the car fields of the pairs in alist,
while assv
uses eqv?
and assq
uses member
and assoc
procedures are the same behaviour as SRFI-1.
list
, but the last argument provides the tail of the
constructed list.(rnrs sorting (6))
library provides procedures for sorting lists
and vectors.list-sort
and vector-sort
procedures perform a stable sort
of list or vector in ascending order according to proc, without
changing list or vector in any way. The list-sort
procedure
returns a list, and vector-sort
returns a vector. The results may be
eq?
to the argument when the argument is already sorted, and the result
of list-sort
may share structure with a tail of the original list. The
sorting algorithm performs O(n lg n) calls to proc where n is the length
of list or vector, and all arguments passed to proc are
elements of the list or vector being sorted, but the pairing of
arguments and the sequencing of calls to proc are not specified. If
multiple returns occur from list-sort
or vector-sort
, the
return values returned by earlier returns are not mutated.
If the optional argument start and end for vector-sort
is specified, then the sorting range is restricted by the given start
(inclusive) and end (exclusive).
vector-sort!
procedure destructively sorts vector in
ascending order according to proc.
If the optional argument start and end is specified, then
the sorting range is restricted by the given start (inclusive)
and end (exclusive).
(rnrs control (6))
library, which provides useful control structures.when
expression is evaluated by evaluating the test expression.
If test evaluates to a true value, the remaining expressions are
evaluated in order, and the results of the last expression are returned as
the results of the entire when
expression. Otherwise, the when
expression returns unspecified values. An unless
expression is evaluated
by evaluating the test expression. If test evaluates to #f, the
remaining expressions are evaluated in order, and the results of the last
expression are returned as the results of the entire unless
expression. Otherwise, the unless
expression returns unspecified values.
do
expression is an iteration construct. It specifies a set of variables
to be bound, how they are to be initialized at the start, and how they are to be
updated on each iteration.
A do
expression is evaluated as follows: The init expressions are
evaluated (in some unspecified order), the variables are bound to fresh
locations, the results of the init expressions are stored in the bindings
of the variables, and then the iteration phase begins.
Each iteration begins by evaluating test if the result is #f, then the
commands are evaluated in order for effect, the step expressions are
evaluated in some unspecified order, the variables are bound to fresh
locations holding the results, and the next iteration begins.
If test evaluates to a true value, the expressions are evaluated from
left to right and the values of the last expression are returned. If no
expressions are present, then the do
expression returns unspecified
values.
The region of the binding of a variable consists of the entire do
expression except for the inits.
A step may be omitted, in which case the effect is the same as if
(variable init variable) had been written instead of
(variable init).
(do ((vec (make-vector 5)) (i 0 (+ i 1))) ((= i 5) vec) (vector-set! vec i i))=> #(0 1 2 3 4)
(let ((x '(1 3 5 7 9))) (do ((x x (cdr x)) (sum 0 (+ sum (car x)))) ((null? x) sum)))=> 25
(formals body)Formals must be as in a
lambda
form.
A case-lambda
expression evaluates to a procedure. This procedure, when
applied, tries to match its arguments to the case-lambda-clauses
in order.
The arguments match a clause if one of the following conditions is fulfilled:
Formals has the form (variable ...)
and the number of
arguments is the same as the number of formal parameters in formals.
Formals has the form
(variable1 ... variablen . variablen+1)and the number of arguments is at least n. Formals has the form variable. For the first clause matched by the arguments, the variables of the formals are bound to fresh locations containing the argument values in the same arrangement as with
lambda
.
The last expression of a body in a case-lambda
expression is in tail context.
If the arguments match none of the clauses, an exception with condition type
&assertion
is raised.
(rnrs records syntactic (6))
library. Some details of the
specification are explained in terms of the specification of the procedural
layer below.
define-record-type
form defines a record type along with
associated constructor descriptor and constructor, predicate, field accessors,
and field mutators. The define-record-type
form expands into a set of
definitions in the environment where define-record-type
appears; hence,
it is possible to refer to the bindings (except for that of the record type
itself) recursively.
The name-spec specifies the names of the record type, constructor, and
predicate. It must take one of the following forms:
(record-name constructor-name predicate-name)
record-nameRecord-name, constructor-name, and predicate-name must all be identifiers. Record-name, taken as a symbol, becomes the name of the record type. (See the description of
protocol
clause, or,
in its absence, using a default protocol. For details, see the description of the
protocol
clause below.
Predicate-name is defined by this definition to a predicate for the defined
record type.
The second form of name-spec is an abbreviation for the first form, where
the name of the constructor is generated by prefixing the record name with
make-
, and the predicate name is generated by adding a question mark
(?
) to the end of the record name. For example, if the record name is
frob
, the name of the constructor is make-frob
, and the predicate
name is frob?
.
Each record-clause must take one of the auxiliary syntax forms; it is a
syntax violation if multiple record-clauses of the same kind appear in a
define-record-type
form.
(fields field-spec*)Each field-spec has one of the following forms
(immutable field-name accessor-name)
(mutable field-name accessor-name mutator-name)
(immutable field-name)
(mutable field-name)
field-nameField-name, accessor-name, and mutator-name must all be identifiers. The first form declares an immutable field called field-name>, with the corresponding accessor named accessor-name. The second form declares a mutable field called field-name, with the corresponding accessor named accessor-name, and with the corresponding mutator named mutator-name. If field-spec takes the third or fourth form, the accessor name is generated by appending the record name and field name with a hyphen separator, and the mutator name (for a mutable field) is generated by adding a
-set!
suffix to the
accessor name. For example, if the record name is frob
and the field name
is widget
, the accessor name is frob-widget
and the mutator name is
frob-widget-set!
.
If field-spec is just a field-name form, it is an abbreviation for
(immutable field-name)
.
The field-names become, as symbols, the names of the fields in the
record-type
descriptor being created, in the same order.
The fields
clause may be absent; this is equivalent to an empty fields
clause.
(parent parent-name)Specifies that the record type is to have parent type parent-name, where parent-name is the record-name of a record type previously defined using
define-record-type
. The record-type definition associated with
parent-name must not be sealed. If no parent clause and no parent-rtd
(see below) clause is present, the record type is a base type.
(protocol expression)Expression is evaluated in the same environment as the
define-record-type
form, and must evaluate to a protocol appropriate for the record type being defined.
The protocol is used to create a record-constructor descriptor as described below.
If no protocol
clause is specified, a constructor descriptor is still created
using a default protocol. The clause can be absent only if the record type being
defined has no parent type, or if the parent definition does not specify a protocol.
(sealed boolean)If this option is specified with operand #t, the defined record type is sealed, i.e., no extensions of the record type can be created. If this option is specified with operand #f, or is absent, the defined record type is not sealed.
(opaque boolean)If this option is specified with operand #t, or if an opaque parent record type is specified, the defined record type is opaque. Otherwise, the defined record type is not opaque. See the specification of record-rtd below for details.
(nongenerative uid)
(nongenerative)This specifies that the record type is nongenerative with uid uid, which must be an identifier. If uid is absent, a unique uid is generated at macro-expansion time. If two record-type definitions specify the same uid, then the record-type definitions should be equivalent, i.e., the implied arguments to
make-record-type-descriptor
must be equivalent as described under
make-record-type-descriptor
. If this condition is not met, it is either
considered a syntax violation or an exception with condition type &assertion
is raised. If the condition is met, a single record type is generated for both
definitions.
In the absence of a nongenerative
clause, a new record type is generated
every time a define-record-type
form is evaluated:
(let ((f (lambda (x) (define-record-type r ...) (if x r? (make-r ...))))) ((f #t) (f #f)))=> #f
(parent-rtd parent-rtd parent-cd)Specifies that the record type is to have its parent type specified by parent-rtd, which should be an expression evaluating to a record-type descriptor, and parent-cd, which should be an expression evaluating to a constructor descriptor. The record-type definition associated with the value of parent-rtd must not be sealed. Moreover, a record-type definition must not have both a
parent
and a parent-rtd
clause.
All bindings created by define-record-typ
e (for the record type, the
constructor, the predicate, the accessors, and the mutators) must have names that
are pairwise distinct.
The constructor created by a define-record-type
form is a procedure as
follows:
parent
clause and no protocol
clause, the
constructor accepts as many arguments as there are fields, in the same order
as they appear in the fields
clause, and returns a record object with
the fields initialized to the corresponding arguments.parent
or parent-rtd
clause and a protocol
clause, the protocol expression must evaluate to a procedure that accepts a
single argument. The protocol procedure is called once during the evaluation of
the define-record-type
form with a procedure p as its argument. It
should return a procedure, which will become the constructor bound to
constructor-name. The procedure p accepts as many arguments as there
are fields, in the same order as they appear in the fields clause, and returns
a record object with the fields initialized to the corresponding arguments.
The constructor returned by the protocol procedure can accept an arbitrary number
of arguments, and should call p once to construct a record object, and
return that record object.
For example, the following protocol expression for a record-type definition with
three fields creates a constructor that accepts values for all fields, and
initialized them in the reverse order of the arguments:
(lambda (p) (lambda (v1 v2 v3) (p v3 v2 v1)))
parent
clause and a protocol
clause, then
the protocol procedure is called once with a procedure nas its argument.
As in the previous case, the protocol procedure should return a procedure, which
will become the constructor bound to constructor-name. However, n is
different from p in the previous case: It accepts arguments corresponding
to the arguments of the constructor of the parent type. It then returns a procedure
p that accepts as many arguments as there are (additional) fields in this
type, in the same order as in the fields
clause, and returns a record object
with the fields of the parent record types initialized according to their constructors
and the arguments to n, and the fields of this record type initialized to
its arguments of p.
The constructor returned by the protocol procedure can accept an arbitrary number
of arguments, and should call n once to construct the procedure p,
and call p once to create the record object, and finally return that record
object.
For example, the following protocol expression assumes that the constructor of
the parent type takes three arguments:
(lambda (n) (lambda (v1 v2 v3 x1 x2 x3 x4) (let ((p (n v1 v2 v3))) (p x1 x2 x3 x4))))The resulting constructor accepts seven arguments, and initializes the fields of the parent types according to the constructor of the parent type, with
v1
,
v2
, and v3
as arguments. It also initializes the fields of this
record type to the values of x1
, ..., x4
.
parent
clause, but no protocol
clause, then the
parent type must not have a protocol
clause itself. The constructor bound
to constructor-name is a procedure that accepts arguments corresponding to
the parent types' constructor first, and then one argument for each field in the
same order as in the fields
clause. The constructor returns a record object
with the fields initialized to the corresponding arguments.
parent-rtd
clause, then the constructor is as with a
parent
clause, except that the constructor of the parent type is determined
by the constructor descriptor of the parent-rtd
clause.
(define-record-type frob (fields (mutable widget)) (protocol (lambda (p) (lambda (n) (p (make-widget n))))))is equivalent to the following explicit-naming record definition.
(define-record-type (frob make-frob frob?) (fields (mutable widget frob-widget frob-widget-set!)) (protocol (lambda (p) (lambda (n) (p (make-widget n))))))Also, the implicit-naming record definition:
(define-record-type point (fields x y))is equivalent to the following explicit-naming record definition:
(define-record-type (point make-point point?) (fields (immutable x point-x) (immutable y point-y)))With implicit naming, it is still possible to specify some of the names explicitly; for example, the following overrides the choice of accessor and mutator names for the widget field.
(define-record-type frob (fields (mutable widget getwid setwid!)) (protocol (lambda (p) (lambda (n) (p (make-widget n))))))
record?
procedure from the
(rnrs records inspection (6))
library:
(define-record-type (point make-point point?) (fields (immutable x point-x) (mutable y point-y set-point-y!)) (nongenerative point-4893d957-e00b-11d9-817f-00111175eb9e))
(define-record-type (cpoint make-cpoint cpoint?) (parent point) (protocol (lambda (n) (lambda (x y c) ((n x y) (color->rgb c))))) (fields (mutable rgb cpoint-rgb cpoint-rgb-set!)))
(define (color->rgb c) (cons 'rgb c))
(define p1 (make-point 1 2))
(define p2 (make-cpoint 3 4 'red))
(point? p1)=> #t
(point? p2)=> #t
(point? (vector))=> #f
(point? (cons 'a 'b))=> #f
(cpoint? p1)=> #f
(cpoint? p2)=> #t
(point-x p1)=> 1
(point-y p1)=> 2
(point-x p2)=> 3
(point-y p2)=> 4
(cpoint-rgb p2)=> (rgb . red)
(set-point-y! p1 17)=> unspecified
(point-y p1)=> 17
(record-rtd p1)=> (record-type-descriptor point)
(define-record-type (ex1 make-ex1 ex1?) (protocol (lambda (p) (lambda a (p a)))) (fields (immutable f ex1-f)))
(define ex1-i1 (make-ex1 1 2 3))
(ex1-f ex1-i1)=> (1 2 3)
(define-record-type (ex2 make-ex2 ex2?) (protocol (lambda (p) (lambda (a . b) (p a b)))) (fields (immutable a ex2-a) (immutable b ex2-b)))
(define ex2-i1 (make-ex2 1 2 3))
(ex2-a ex2-i1)=> 1
(ex2-b ex2-i1)=> (2 3)
(define-record-type (unit-vector make-unit-vector unit-vector?) (protocol (lambda (p) (lambda (x y z) (let ((length (sqrt (+ (* x x) (* y y) (* z z))))) (p (/ x length) (/ y length) (/ z length)))))) (fields (immutable x unit-vector-x) (immutable y unit-vector-y) (immutable z unit-vector-z)))
(define *ex3-instance* #f)
(define-record-type ex3 (parent cpoint) (protocol (lambda (n) (lambda (x y t) (let ((r ((n x y 'red) t))) (set! *ex3-instance* r) r)))) (fields (mutable thickness)) (sealed #t) (opaque #t))
(define ex3-i1 (make-ex3 1 2 17))
(ex3? ex3-i1)=> #t
(cpoint-rgb ex3-i1)=> (rgb . red)
(ex3-thickness ex3-i1)=> 17
(ex3-thickness-set! ex3-i1 18)=> unspecified
(ex3-thickness ex3-i1)=> 18
*ex3-instance*=> ex3-i1
(record? ex3-i1)=> #f
(rnrs records procedural (6))
library.
&assertion
is raised if parent is sealed
(see below).
The uid argument must be either #f or a symbol. If uid is a symbol,
the record-creation operation is nongenerative i.e., a new record type is created
only if no previous call to make-record-type-descriptor
was made with the
uid. If uid is #f, the record-creation operation is generative,
.e., a new record type is created even if a previous call to
make-record-type-descriptor
was made with the same arguments.
If make-record-type-descriptor
is called twice with the same uid
symbol, the parent arguments in the two calls must be eqv?
, the
fields arguments equal?
, the sealed? arguments boolean-equivalent
(both #f or both true), and the opaque? arguments boolean-equivalent. If
these conditions are not met, an exception with condition type &assertion
is raised when the second call occurs. If they are met, the second call returns,
without creating a new record type, the same record-type descriptor (in the
sense of eqv?
) as the first call.
The sealed? flag must be a boolean. If true, the returned record type is
sealed, i.e., it cannot be extended.
The opaque? flag must be a boolean. If true, the record type is opaque. If
passed an instance of the record type, record? returns #f. Moreover, if
record-rtd
(see (rnrs records inspection (6)))
is called with an instance of the record type, an exception with condition
type &assertion
is raised. The record type is also opaque if an opaque
parent is supplied. If opaque? is #f and an opaque parent is not supplied,
the record is not opaque.
The fields argument must be a vector of field specifiers. Each field specifier
must be a list of the form (mutable name)
or a list of the form
(immutable name)
. Each name must be a symbol and names the corresponding
field of the record type; the names need not be distinct. A field identified as
mutable may be modified, whereas, when a program attempts to obtain a mutator for
a field identified as immutable, an exception with condition type &assertion
is raised. Where field order is relevant, e.g., for record construction and field
access, the fields are considered to be ordered as specified, although no particular
order is required for the actual representation of a record instance.
The specified fields are added to the parent fields, if any, to determine the
complete set of fields of the returned record type. If fields is modified after
make-record-type-descriptor
has been called, the effect on the returned
rtd is unspecified.
A generative record-type descriptor created by a call to
make-record-type-descriptor
is not eqv?
to any record-type descriptor
(generative or nongenerative) created by another call to
make-record-type-descriptor
. A generative record-type descriptor is eqv?
only to itself, i.e., (eqv? rtd1 rtd2) iff (eq? rtd1 rtd2). Also, two nongenerative
record-type descriptors are eqv?
if they were created by calls to
make-record-type-descriptor
with the same uid arguments.
record-constructor
.
A constructor descriptor can also be used to create other constructor descriptors
for subtypes of its own record type. Rtd must be a record-type descriptor.
Protocol must be a procedure or #f. If it is #f, a default protocol procedure
is supplied.
If protocol is a procedure, it is handled analogously to the protocol
expression in a define-record-type
form.
If rtd is a base record type and protocol is a procedure,
parent-constructor-descriptor must be #f. In this case, protocol
is called by record-constructor
with a single argument p. P
is a procedure that expects one argument for every field of rtd and returns
a record with the fields of rtd initialized to these arguments. The
procedure returned by protocol should call p once with the number of
arguments p expects and return the resulting record as shown in the
simple example below:
(lambda (p) (lambda (v1 v2 v3) (p v1 v2 v3)))Here, the call to p returns a record whose fields are initialized with the values of
v1
, v2
, and v3
. The expression above is
equivalent to (lambda (p) p)
. Note that the procedure returned by protocol
is otherwise unconstrained; specifically, it can take any number of arguments.
If rtd is an extension of another record type parent-rtd and
protocol is a procedure, parent-constructor-descriptor must be a
constructor descriptor of parent-rtd or #f. If
parent-constructor-descriptor is a constructor descriptor, protocol
it is called by record-constructor with a single argument n, which
is a procedure that accepts the same number of arguments as the constructor of
parent-constructor-descriptor and returns a procedure p that, when
called, constructs the record itself. The p procedure expects one argument
for every field of rtd (not including parent fields) and returns a record
with the fields of rtd initialized to these arguments, and the fields of
parent-rtd and its parents initialized as specified by
parent-constructor-descriptor.
The procedure returned by protocol should call n once with the number
of arguments n expects, call the procedure p it returns once with
the number of arguments p expects and return the resulting record. A
simple protocol in this case might be written as follows:
(lambda (n) (lambda (v1 v2 v3 x1 x2 x3 x4) (let ((p (n v1 v2 v3))) (p x1 x2 x3 x4))))This passes arguments
v1
, v2
, v3
to n for
parent-constructor-descriptor and calls p with x1
, ...,
x4
to initialize the fields of rtd itself.
Thus, the constructor descriptors for a record type form a sequence of protocols
parallel to the sequence of record-type parents. Each constructor descriptor in
the chain determines the field values for the associated record type. Child record
constructors need not know the number or contents of parent fields, only the number
of arguments accepted by the parent constructor.
Protocol may be #f, specifying a default constructor that accepts one
argument for each field of rtd (including the fields of its parent type,
if any). Specifically, if rtd is a base type, the default protocol procedure
behaves as if it were (lambda (p) p)
. If rtd is an extension of
another type, then parent-constructor-descriptor must be either #f or
itself specify a default constructor, and the default protocol procedure behaves
as if it were:
(lambda (n) (lambda (v1 ... vj x1 ... xk) (let ((p (n v1 ... vj))) (p x1 ... xk))))The resulting constructor accepts one argument for each of the record type's complete set of fields (including those of the parent record type, the parent's parent record type, etc.) and returns a record with the fields initialized to those arguments, with the field values for the parent coming before those of the extension in the argument list. (In the example, j is the complete number of fields of the parent type, and k is the number of fields of rtd itself.) If rtd is an extension of another record type, and parent-constructor-descriptor or the protocol of parent-constructor-descriptor is #f, protocol must also be #f, and a default constructor descriptor as described above is also assumed.
make-record-constructor-descriptor
) and returns the resulting constructor
constructor for records of the record type associated with
constructor-descriptor.
record-accessor
procedure returns a one-argument procedure whose argument
must be a record of the type represented by rtd. This procedure returns
the value of the selected field of that record.
The field selected corresponds to the kth element (0-based) of the fields
argument to the invocation of make-record-type-descriptor
that created
rtd. Note that k cannot be used to specify a field of any type
rtd extends.
record-mutator
procedure returns a two-argument procedure whose arguments
must be a record record r of the type represented by rtd and an
object obj. This procedure stores obj within the field of r
specified by k. The k argument is as in record-accessor
. If
k specifies an immutable field, an exception with condition type
&assertion
is raised. The mutator returns unspecified values.
(rnrs records inspection (6))
library provides procedures for
inspecting records and their record-type descriptors. These procedures are designed
to allow the writing of portable printers and inspectors.
&assertion
.
make-record-type-descriptor
.
record-accessor
.
(rnrs exceptions (6))
library.
with-exception-handler
procedure returns the results of invoking
thunk. When an exception is raised, handler will be invoked with
the exception.
cond
.
and else
are the same as in the (rnrs base (6))
library.
Evaluating a guard
form evaluates body with an exception handler
that binds the raised object to variable and within the scope of that
binding evaluates the clauses as if they were the clauses of a cond
expression. If every cond-clause's test evaluates to #f and there is
no else
clause, then raise is re-invoked on the raised object.
(rnrs conditions (6))
library for creating and
inspecting condition types and values. A condition value encapsulates information
about an exceptional situation.
condition
procedure returns a condition object with the
components of the conditions as its components, in the same order. The
returned condition is compound if the total number of components is zero or
greater than one. Otherwise, it may be compound or simple.
simple-conditions
procedure returns a list of the
components of condition, in the same order as they appeared in the
construction of condition.
&condition
. The condition-predicate
procedure returns a procedure
that takes one argument. This procedure returns #t if its argument is a condition
of the condition type represented by rtd, i.e., if it is either a simple
condition of that record type (or one of its subtypes) or a compound conditition
with such a simple condition as one of its components, and #f otherwise.
&condition
. Proc should accept one argument, a record of the
record type of rtd. The condition-accessor
procedure returns a
procedure that accepts a single argument, which must be a condition of the type
represented by rtd. This procedure extracts the first component of the
condition of the type represented by rtd, and returns the result of
applying proc to that component.
(field accessor)where both field and accessor must be identifiers. The
define-condition-type
form expands into a record-type definition for
a record type condition-type. The record type will be non-opaque, non-sealed,
and its fields will be immutable. It will have supertype has its parent type.
The remaining identifiers will be bound as follows:
+ &condition + &warning + &serious + &error + &violation + &assertion + &non-continuable + &implementation-restriction + &lexical + &syntax + &undefined + &message + &irritants
error
and assertion-violation
procedures.error
and assertion-violation
procedures, and the syntax-violation
procedure.(rnrs io ports (6))
and (rnrs io simple (6))
libraries.
They are also exported by the (rnrs files (6))
library.
&i/o-port-error
condition.+ &error(See (rnrs conditions (6))) + &i/o + &i/o-read + &i/o-write + &i/o-invalid-position + &i/o-filename + &i/o-file-protection + &i/o-file-is-read-only + &i/o-file-already-exists + &i/o-file-does-not-exist + &i/o-port-error
(rnrs io ports (6))
library defines an I/O layer for
conventional, imperative buffered input and output. A port represents
a buffered access object for a data sink or source or both simultaneously.
The library allows ports to be created from arbitrary data sources and sinks.
The (rnrs io ports (6))
library distinguishes between input ports
and output ports. An input port is a source for data, whereas an output
port is a sink for data. A port may be both an input port and an output port;
such a port typically provides simultaneous read and write access to a file or
other data.
The (rnrs io ports (6))
library also distinguishes between
binary ports, which are sources or sinks for uninterpreted bytes,
and textual ports, which are sources or sinks for characters and strings.
This section uses input-port, output-port, binary-port,
textual-port, binary-input-port, textual-input-port,
binary-output-port, textual-output-port, and port as parameter
names for arguments that must be input ports (or combined input/output ports),
output ports (or combined input/output ports), binary ports, textual ports,
binary input ports, textual input ports, binary output ports, textual output
ports, or any kind of port, respectively.
file-options
object that encapsulates flags to specify how the file is to
be opened. A file-options
object is an enum-set
(see (rnrs enums (6))) over the symbols constituting
valid file options. A file-options parameter name means that the
corresponding argument must be a file-options object.
(file-options)
specifies that the file is created if
it does not exist and an exception with condition type
&i/o-file-already-exists
is raised if it does exist. The following
standard options can be included to modify the default behaviour.
no-create
If the file does not already exist, it is not created;
instead, an exception with condition type &i/o-file-does-not-exist
is
raised. If the file already exists, the exception with condition type
&i/o-file-already-exists
is not raised and the file is truncated to zero
length.
no-fail
If the file already exists, the exception with condition
type &i/o-file-already-exists
is not raised, even if no-create
is
not included, and the file is truncated to zero length.
no-truncate
If the file already exists and the exception with
condition type &i/o-file-already-exists
has been inhibited by inclusion
of no-create
or no-fail
, the file is not truncated, but the port's
current position is still set to the beginning of the file.
append
Among with no-truncate
, set the opened port's
position the end of the file. This is not a part of R6RS specification.
none
, line
, and block
. The result is the corresponding
symbol, and specifies the associated buffer mode.
eqv?
to the result of any other call to the same procedure.lf
, cr
, crlf
, nel
, crnel
, ls
, and
none
. The form evaluates to the corresponding symbol. If the name of
eol-style-symbol is not one of these symbols, it still returns given
symbol, however make-transcoder
does not accept it.
ignore
, raise
, and replace
. The form evaluates to
the corresponding symbol.
The error-handling
mode of a transcoder specifies the behavior of textual
I/O operations in the presence of encoding or decoding errors.
If a textual input operation encounters an invalid or incomplete character
encoding, and the error-handling mode is ignore
, an appropriate number
of bytes of the invalid encoding are ignored and decoding continues with the
following bytes. If the error-handling mode is replace
, the replacement
character U+FFFD is injected into the data stream, an appropriate number of
bytes are ignored, and decoding continues with the following bytes. If the
error-handling mode is raise
, an exception with condition type
&i/o-decoding
is raised.
If a textual output operation encounters a character it cannot encode, and the
error-handling mode is ignore
, the character is ignored and encoding
continues with the next character. If the error-handling mode is replace
,
a codec-specific replacement character is emitted by the transcoder, and
encoding continues with the next character. The replacement character is U+FFFD
for transcoders whose codec is one of the Unicode encodings, but is the ?
character for the Latin-1 encoding. If the error-handling mode is raise
,
an exception with condition type &i/o-encoding
is raised.
replace
. The result is a
transcoder with the behaviour specified by its arguments.
make-transcoder
, they return the codec,
eol-style, and handling-mode arguments, respectively.
textual-port?
procedure returns #t if obj
is textual port, otherwise #f.
The binary-port?
procedure returns #t if obj is binary port,
otherwise #f.transcoded-port
procedure returns a new textual port
with the specified transcoder. Otherwise the new textual port's state is
largely the same as that of binary-port. If binary-port is an input
port, the new textual port will be an input port and will transcode the bytes
that have not yet been read from binary-port. If binary-port is an
output port, the new textual port will be an output port and will transcode
output characters into bytes that are written to the byte sink represented by
binary-port.
port-has-port-position?
procedure returns #t if the
port supports the port-position operation, and #f otherwise.
The port-position procedure returns the index of the position at which the
next position would be read from or written to the port as an exact non-negative
integer object.
port-has-set-port-position!?
procedure returns #t if the
port supports the set-port-position!
operation, and #f otherwise.
The set-port-position!
procedure raises an exception with condition type
&assertion
if the port does not support the operation, and an exception
with condition type &i/o-invalid-position
if pos is not in the range of
valid positions of port. Otherwise, it sets the current position of the
port to pos. If port is an output port,
set-port-position! first flushes port.
The optional argument whence must be one of the following symbols;
begin
current
end
begin
even though user specified it
as current
or end
.
close-port
procedure returns unspecified
values.
call-with-port
procedure calls proc with port as an argument. If proc
returns, port is closed automatically and the values returned by
proc are returned. If proc does not return, port is not
closed automatically, except perhaps when it is possible to prove that
port will never again be used for an input or output operation.
get-char
raises
an get-char
may successfully decode a character if bytes completing the
encoding are available after the end of file.
lookahead-u8
procedure (if
input-port is a binary port) or the lookahead-char
procedure (if
input-port is a textual port) would return the end-of-file object, and
#f otherwise.
(file-options)
.
The buffer-mode argument, if supplied, must be one of the symbols that
name a buffer mode. The buffer-mode argument defaults to block
.
If maybe-transcoder is a transcoder, it becomes the transcoder associated
with the returned port.
If maybe-transcoder is #f or absent, the port will be a binary port,
otherwise the port will be textual port.
open-bytevector-input-port
procedure returns an input port whose
bytes are drawn from bytevector. If transcoder is specified, it
becomes the transcoder associated with the returned port.
If transcoder is #f or absent, the port will be a binary port,
otherwise the port will be textual port.
Optional arguments start and end restricts the range of
input bytevector. It is almost the same as following code but doesn't
allocate extra memory;
(open-bytevector-input-port (bytevector-copy bytevector start end))
(open-string-input-port (substring string start end))These procedures reuse the given arguments, thus if bytevector is modified after
open-bytevector-input-port
has been called, it affects the result
of the port. So does open-string-input-port
.
current-input-port
sets the
port as a default port for input. Otherwise it returns a default input
port.Start will be a non-negative exact integer object, count will be a positive exact integer object, and bytevector will be a bytevector whose length is at least start + count. The read! procedure should obtain up to count bytes from the byte source, and should write those bytes into bytevector starting at index start. The read! procedure should return an exact integer object. This integer object should represent the number of bytes that it has read. To indicate an end of file, the read! procedure should write no bytes and return 0.
The get-position procedure (if supplied) should return an exact integer
object representing the current position of the input port. If not supplied, the
custom port will not support the port-position
operation.
Pos will be a non-negative exact integer object. The set-position! procedure (if supplied) should set the position of the input port to pos. If not supplied, the custom port will not support the set-port-position! operation.
The close procedure (if supplied) should perform any actions that are necessary when the input port is closed.
The ready procedure (if supplied) should indicate the port data are ready or not.
Start will be a non-negative exact integer object, count will be a positive exact integer object, and string will be a string whose length is at least start + count. The read! procedure should obtain up to count characters from the character source, and should write those characters into string starting at index start. The read! procedure should return an exact integer object representing the number of characters that it has written. To indicate an end of file, the read! procedure should write no bytes and return 0.
The get-position procedure (if supplied) should return a single value.
The return value should represent the current position of the input port. If not
supplied, the custom port will not support the port-position
operation.
The set-position! procedure (if supplied) should set the position of
the input port to pos if pos is the return value of a call to
get-position. If not supplied, the custom port will not support the
set-port-position!
operation.
The close procedure (if supplied) should perform any actions that are necessary when the input port is closed.
The ready procedure (if supplied) should indicate the port characters are ready or not.
get-u8
returns the byte as an octet and
updates binary-input-port to point just past that byte. If no input byte
is seen before an end of file is reached, the end-of-file object is returned.
lookahead-u8
procedure is like get-u8
, but it
does not update binary-input-port to point past the byte.get-bytevector-n
procedure reads from binary-input-port,
blocking as necessary, until count bytes are available from
binary-input-port or until an end of file is reached. If count
bytes are available before an end of file, get-bytevector-n
returns a
bytevector of size count.
If fewer bytes are available before an end of file, get-bytevector-n
returns a bytevector containing those bytes. In either case, the input port is
updated to point just past the bytes read. If an end of file is reached before
any bytes are available, get-bytevector-n
returns the end-of-file object.
get-bytevector-n!
procedure reads from binary-input-port,
blocking as necessary, until count bytes are available from
binary-input-port or until an end of file is reached. If count bytes
are available before an end of file, they are written into bytevector
starting at index start, and the result is count. If fewer bytes are
available before the next end of file, the available bytes are written into
bytevector starting at index start, and the result is a number object
representing the number of bytes actually read. In either case, the input port is
updated to point just past the bytes read. If an end of file is reached before
any bytes are available, get-bytevector-n!
returns the end-of-file object.
get-bytevector-some
returns a freshly
allocated bytevector containing the initial available bytes (at least one and
maximum 512 bytes), and it updates binary-input-port to point just past
these bytes. If no input bytes are seen before an end of file is reached, the
end-of-file object is returned.
get-bytevector-all
returns a
bytevector containing all bytes up to the next end of file. Otherwise,
get-bytevector-all
returns the end-of-file object.
These procedures can take optional argument reckless. If this is given,
these procedures can read bytes from textual port. This optional argument is for
socket programming. Users needs to make sure that the given port can be read as
textual port after reading port recklessly.
get-char
returns that character and updates the input port to point past the character.
If an end of file is reached before any character is read, get-char
returns the end-of-file object.
lookahead-char
procedure is like get-char
, but it
does not update textual-input-port to point past the character.
get-string-n
procedure reads from textual-input-port, blocking
as necessary, until count characters are available, or until an end of
file is reached.
If count characters are available before end of file, get-string-n
returns a string consisting of those count characters. If fewer characters
are available before an end of file, but one or more characters can be read,
get-string-n
returns a string containing those characters. In either case,
the input port is updated to point just past the characters read. If no characters
can be read before an end of file, the end-of-file object is returned.
get-string-n!
procedure reads from textual-input-port in the
same manner as get-string-n
. If count characters are available before
an end of file, they are written into string starting at index start,
and count is returned. If fewer characters are available before an end of
file, but one or more can be read, those characters are written into string
starting at index start and the number of characters actually read is
returned as an exact integer object. If no characters can be read before an end
of file, the end-of-file object is returned.
get-string-n
and get-string-n!
.
If characters are available before the end of file, a string containing all the
characters decoded from that data are returned. If no character precedes the end
of file, the end-of-file object is returned.
get-string-n
and get-string-n!
.
If a linefeed character is read, a string containing all of the text up to (but
not including) the linefeed character is returned, and the port is updated to
point just past the linefeed character. If an end of file is encountered before
any linefeed character is read, but some characters have been read and decoded
as characters, a string containing those characters is returned. If an end of
file is encountered before any characters are read, the end-of-file object is
returned.
get-datum
procedure returns the next
datum that can be parsed from the given textual-input-port, updating
textual-input-port to point exactly past the end of the external
representation of the object.
If a character inconsistent with an external representation is encountered in
the input, an exception with condition types &lexical
and &i/o-read
is raised. Also, if the end of file is encountered after the beginning of an
external representation, but the external representation is incomplete and
therefore cannot be parsed, an exception with condition types &lexical
and &i/o-read
is raised.
flush-output-port
procedure returns unspecified values.
If the optional argument is omitted then (current-output-port)
will be
used.
open-file-output-port
procedure returns an output port for the named
file.
The file-options argument, which may determine various aspects of the
returned port, defaults to the value of (file-options)
.
The buffer-mode argument, if supplied, must be one of the symbols that
name a buffer mode. The buffer-mode argument defaults to block
.
If maybe-transcoder is a transcoder, it becomes the transcoder associated
with the port.
If maybe-transcoder is #f or absent, the port will be a binary port,
otherwise the port will be textual port.
open-bytevector-output-port
procedure returns two values: an output
port and an extraction procedure. The output port accumulates the bytes written
to it for later extraction by the procedure.
If maybe-transcoder is a transcoder, it becomes the transcoder associated
with the port. If maybe-transcoder is #f or absent, the port will be a
binary port, otherwise the port will be textual port.
The extraction procedure takes no arguments. When called, it returns a bytevector
consisting of all the port's accumulated bytes (regardless of the port's current
position), removes the accumulated bytes from the port, and resets the port's
position.
call-with-bytevector-output-port
procedure creates an output port that
accumulates the bytes written to it and calls proc with that output port as
an argument. Whenever proc returns, a bytevector consisting of all of the
port's accumulated bytes (regardless of the port's current position) is returned
and the port is closed.
The transcoder associated with the output port is determined as for a call to
open-bytevector-output-port
.
call-with-string-output-port
procedure creates a textual output port
that accumulates the characters written to it and calls proc with that
output port as an argument. Whenever proc returns, a string consisting of all of
the port's accumulated characters (regardless of the port's current position) is
returned and the port is closed.
make-custom-binary-input-port
.
Start and count will be non-negative exact integer objects, and bytevector will be a bytevector whose length is at least start + count. The write! procedure should write up to count bytes from bytevector starting at index start to the byte sink. If count is 0, the write! procedure should have the effect of passing an end-of-file object to the byte sink. In any case, the write! procedure should return the number of bytes that it wrote, as an exact integer object.
make-custom-textual-input-port
.
Start and count will be non-negative exact integer objects, and string will be a string whose length is at least start + count. The write! procedure should write up to count characters from string starting at index start to the character sink. If count is 0, the write! procedure should have the effect of passing an end-of-file object to the character sink. In any case, the write! procedure should return the number of characters that it wrote, as an exact integer object.
(bytevector-length bytevector)
- start,
respectively. Bytevector must have a length of at least start + count.
The put-bytevector
procedure writes the count bytes of the bytevector
bytevector starting at index start to the output port. The
put-bytevector
procedure returns unspecified values.
(string-length string)
- start. The put-string
procedure
writes the count characters of string starting at index start to the
port. The put-string
procedure returns unspecified values.
put-datum
procedure
writes an external representation of datum to textual-output-port.
open-file-output-port
. If the input/output port supports
port-position
and/or set-port-position!
, the same port position
is used for both input and output.
make-custom-binary-input-port
and
make-custom-binary-output-port
procedures.
Each of the remaining arguments may be #f; if any of those arguments is not #f,
it must be a procedure and should behave as specified in the description of
make-custom-binary-input-port
.
make-custom-textual-input-port
and
make-custom-textual-output-port
procedures.
Each of the remaining arguments may be #f; if any of those arguments is not #f,
it must be a procedure and should behave as specified in the description of
make-custom-textual-input-port
.
(rnrs io simple (6))
library, which provides
a somewhat more convenient interface for performing textual I/O on ports.
(rnrs io posts (6))
library. I do not write the documentation of it, if
you want to import only this library, make sure which procedures are exported.
You can see it on R6RS.
open-input-file
or
open-output-file
.
open-input-file
or
open-output-file
.
get-char
and lookahead-char
.
If textual-input-port is omitted, it defaults to the value returned by
current-input-port
.
current-input-port
.
current-output-port
.
write-char
to write
#\linefeed
to textual-output-port.
If textual-output-port is omitted, it defaults to the value returned by
current-output-port
.
current-output-port
.
write
procedure operates in the same way
as put-datum
.
If textual-output-port is omitted, it defaults to the value returned by
current-output-port
.
file-exists?
procedure returns #t if the named file exists at the time
the procedure is called, #f otherwise.
delete-file
procedure deletes the named file if it exists and can be
deleted, and returns unspecified values. If the file does not exist or cannot be
deleted, an exception with condition type &i/o-filename
is raised.
&implementation-restriction
is raised if that sum or product is not a
fixnum.
&implementation-restriction
is raised if
the mathematically correct result of this procedure is not a fixnum.
NOTE: R6RS says it raises &assertion
if the result is not fixnum, however
Sagittarius raises &implementation-restriction
for consistency with
fx+
and fx*
.
(rnrs base (6))
section.
(let* ((s (+ fx1 fx2 fx3)) (s0 (mod0 s (expt 2 (fixnum-width)))) (s1 (div0 s (expt 2 (fixnum-width))))) (values s0 s1))
(let* ((d (- fx1 fx2 fx3)) (d0 (mod0 d (expt 2 (fixnum-width)))) (d1 (div0 d (expt 2 (fixnum-width))))) (values d0 d1))
(let* ((s (+ (* fx1 fx2) fx3)) (s0 (mod0 s (expt 2 (fixnum-width)))) (s1 (div0 s (expt 2 (fixnum-width))))) (values s0 s1))
(fxior (fxand fx1 fx2) (fxand (fxnot fx1) fx3))
(fxnot (fxbit-count (fxnot ei)))
(fxnot fx)
if
it is negative, which is the fixnum result of the following computation:
(do ((result 0 (+ result 1)) (bits (if (fxnegative? fx) (fxnot fx) fx) (fxarithmetic-shift-right bits 1))) ((fxzero? bits) result))
(fixnum-width)
.
The fxbit-set?
procedure returns #t if the fx2th bit is 1 in the
two's complement representation of fx1, and #f otherwise. This is the
fixnum result of the following computation:
(not (fxzero? (fxand fx1 (fxarithmetic-shift-left 1 fx2))))
(fixnum-width)
.
Fx3 must be 0 or 1. The fxcopy-bit
procedure returns the result of
replacing the fx2th bit of fx1 by fx3, which is the result of
the following computation:
(let* ((mask (fxarithmetic-shift-left 1 fx2))) (fxif mask (fxarithmetic-shift-left fx3 fx2) fx1))
(fixnum-width)
. Moreover, fx2 must be less than or equal to
fx3. The fxbit-field
procedure returns the number represented by
the bits at the positions from fx2 (inclusive) to fx3 (exclusive),
which is the fixnum result of the following computation:
(let* ((mask (fxnot (fxarithmetic-shift-left -1 fx3)))) (fxarithmetic-shift-right (fxand fx1 mask) fx2))
(fixnum-width)
. Moreover, fx2 must be less than or equal to
fx3. The fxcopy-bit-field
procedure returns the result of replacing
in fx1 the bits at positions from fx2 (inclusive) to fx3
(exclusive) by the corresponding bits in fx4, which is the fixnum result
of the following computation:
(let* ((to fx1) (start fx2) (end fx3) (from fx4) (mask1 (fxarithmetic-shift-left -1 start)) (mask2 (fxnot (fxarithmetic-shift-left -1 end))) (mask (fxand mask1 mask2))) (fxif mask (fxarithmetic-shift-left from start) to))
(fixnum-width)
. If
(floor (* fx1 (expt 2 fx2)))is a fixnum, then that fixnum is returned. Otherwise an exception with condition type
&implementation-restriction
is raised.
(fixnum-width)
.
The fxarithmetic-shift-left
procedure behaves the same as
fxarithmetic-shift
, and (fxarithmetic-shift-right fx1 fx2)
behaves the same as (fxarithmetic-shift fx1 (fx- fx2))
.
(fixnum-width)
. Fx2 must be less than or equal to fx3.
Fx4 must be less than the difference between fx3 and fx2. The
fxrotate-bit-field
procedure returns the result of cyclically permuting
in fx1 the bits at positions from fx2 (inclusive) to fx3
(exclusive) by fx4 bits towards the more significant bits, which is the
result of the following computation:
(let* ((n fx1) (start fx2) (end fx3) (count fx4) (width (fx- end start))) (if (fxpositive? width) (let* ((count (fxmod count width)) (field0 (fxbit-field n start end)) (field1 (fxarithmetic-shift-left field0 count)) (field2 (fxarithmetic-shift-right field0 (fx- width count))) (field (fxior field1 field2))) (fxcopy-bit-field n start end field)) n))
(fixnum-width)
. Moreover, fx2 must be less than or equal to fx3.
The fxreverse-bit-field
procedure returns the fixnum obtained from
fx1 by reversing the order of the bits at positions from fx2
(inclusive) to fx3 (exclusive).
(rnrs arithmetic flonums (6))
library.
This section uses fl, fl1, fl2, etc., as parameter names for
arguments that must be flonums, and ifl as a name for arguments that must
be integer-valued flonums, i.e., flonums for which the integer-valued?
predicate returns true.
flinteger?
procedure tests whether the number
object is an integer, flzero?
tests whether it is fl=?
to zero,
flpositive?
tests whether it is greater than zero, flnegative?
tests whether it is less than zero
, flodd?
tests whether it is
odd, fleven?
tests whether it is even, flfinite?
tests whether
it is not an infinity and not a NaN, flinfinite?
tests whether it is
an infinity, and flnan?
tests whether it is a NaN.
(rnrs base (6))
. For zero divisors, these
procedures may return a NaN or some unspecified flonum.
flfloor
returns the largest
integral flonum not larger than fl. The flceiling
procedure returns
the smallest integral flonum not smaller than fl. The fltruncate
procedure returns the integral flonum closest to fl whose absolute value
is not larger than the absolute value of fl. The flround
procedure
returns the closest integral flonum to fl, rounding to even when fl
represents a number halfway between two integers.
Although infinities and NaNs are not integer objects, these procedures return an
infinity when given an infinity as an argument, and a NaN when given a NaN.
flexp
procedure computes the base-e exponential of fl. The fllog
procedure
with a single argument computes the natural logarithm of fl1
(not the base
ten logarithm); (fllog fl1 fl2)
computes the base-fl2
logarithm of fl1. The flasin
, flacos
, and flatan
procedures compute arcsine, arccosine, and arctangent, respectively.
(flatan fl1 fl2)
computes the arc tangent of fl1/fl2.
flsqrt
returns 0.0; for other negative arguments, the result unspecified flonum.
flexpt
procedure returns fl1
raised to the power fl2. If fl1 is negative and fl2 is not an
integer object, the result is a NaN. If fl1 is zero, then the result is zero.
+ &implementation-restriction (see "Conditions") + &no-infinities + &no-nans
(rnrs arithmetic bitwise (6))
library.
The exact bitwise arithmetic provides generic operations on exact integer
objects. This section uses ei, ei1, ei2, etc., as parameter
names that must be exact integer objects.
(bitwise-ior (bitwise-and ei1 ei2) (bitwise-and (bitwise-not ei1) ei3))
(bitwise-not (bitwise-bit-count (bitwise-not ei)))
(bitwise-not ei)
if it is negative, which is the exact integer
object that is the result of the following computation:
(do ((result 0 (+ result 1)) (bits (if (negative? ei) (bitwise-not ei) ei) (bitwise-arithmetic-shift bits -1))) ((zero? bits) result))
bitwise-bit-set?
procedure returns #t if the ei2th bit is 1 in the two's complement
representation of ei1, and #f otherwise. This is the result of the
following computation:
(not (zero? (bitwise-and (bitwise-arithmetic-shift-left 1 ei2) ei1)))
bitwise-copy-bit
procedure returns the result of replacing the
ei2th bit of ei1 by the ei2th bit of ei3, which is the
result of the following computation:
(let* ((mask (bitwise-arithmetic-shift-left 1 ei2))) (bitwise-if mask (bitwise-arithmetic-shift-left ei3 ei2) ei1))
bitwise-bit-field
procedure returns
he number represented by the bits at the positions from ei2 (inclusive) to
ei3 (exclusive), which is the result of the following computation:
(let ((mask (bitwise-not (bitwise-arithmetic-shift-left -1 ei3)))) (bitwise-arithmetic-shift-right (bitwise-and ei1 mask) ei2))
bitwise-copy-bit-field
procedure
returns the result of replacing in ei1 the bits at positions from
var{ei2} (inclusive) to ei3 (exclusive) by the corresponding bits in
ei4, which is the fixnum result of the following computation:
(let* ((to ei1) (start ei2) (end ei3) (from ei4) (mask1 (bitwise-arithmetic-shift-left -1 start)) (mask2 (bitwise-not (bitwise-arithmetic-shift-left -1 end))) (mask (bitwise-and mask1 mask2))) (bitwise-if mask (bitwise-arithmetic-shift-left from start) to))
(floor (* ei1 (expt 2 ei2)))ei2 must be a fixnum. This is implementation restriction.
bitwise-arithmetic-shift-left
procedure returns the same result as
bitwise-arithmetic-shift
, and
(bitwise-arithmetic-shift-right ei1 ei2)returns the same result as
(bitwise-arithmetic-shift ei1 (- ei2)). ei2 must be a fixnum. This is implementation restriction.
bitwise-rotate-bit-field
procedure returns the result of cyclically
permuting in ei1 the bits at positions from ei2 (inclusive) to
ei3 (exclusive) by ei4 bits towards the more significant bits,
which is the result of the following computation:
(let* ((n ei1) (start ei2) (end ei3) (count ei4) (width (- end start))) (if (positive? width) (let* ((count (mod count width)) (field0 (bitwise-bit-field n start end)) (field1 (bitwise-arithmetic-shift-left field0 count)) (field2 (bitwise-arithmetic-shift-right field0 (- width count))) (field (bitwise-ior field1 field2))) (bitwise-copy-bit-field n start end field)) n))ei4 must be a fixnum. This is implementation restriction.
bitwise-reverse-bit-field
procedure
returns the result obtained from ei1 by reversing the order of the bits at
positions from ei2 (inclusive) to ei3 (exclusive).
(rnrs syntax-case (6))
library provides support for
writing low-level macros in a high-level style, with automatic syntax checking,
input destructuring, output restructuring, maintenance of lexical scoping and
referential transparency (hygiene), and support for controlled identifier capture.
(pattern output-expression)
(pattern fender output-expression)Fender and output-expression must be expressions. Pattern is the same as
syntax-rules
. See
(rnrs base (6)) section.
A syntax-case
expression first evaluates expression. It then attempts to
match the pattern from the first clause against the resulting value,
which is unwrapped as necessary to perform the match. If the pattern
matches the value and no fender is present, output-expression is
evaluated and its value returned as the value of the syntax-case
expression.
If the pattern does not match the value, syntax-case
tries the second
clause, then the third, and so on. It is a syntax violation if the value
does not match any of the patterns.
If the optional fender is present, it serves as an additional constraint on
acceptance of a clause. If the pattern of a given clause matches the
input value, the corresponding fender is evaluated. If fender evaluates
to a true value, the clause is accepted; otherwise, the clause is
rejected as if the pattern had failed to match the value. Fenders are
logically a part of the matching process, i.e., they specify additional matching
constraints beyond the basic structure of the input.
Pattern variables contained within a clause's pattern are bound to the
corresponding pieces of the input value within the clause's fender (if present)
and output-expression. Pattern variables can be referenced only within syntax
expressions (see below). Pattern variables occupy the same name space as program
variables and keywords.
If the syntax-case
form is in tail context, the output-expressions
are also in tail position.
(subtemplate ...)
(subtemplate ... . template)
#(subtemplate ...)A subtemplate is a template followed by zero or more ellipses. The value of a
syntax
form is a copy of template in which the
pattern variables appearing within the template are replaced with the input
subforms to which they are bound. Pattern data and identifiers that are not
pattern variables or ellipses are copied directly into the output. A
subtemplate followed by an ellipsis expands into zero or more occurrences
of the subtemplate. Pattern variables that occur in subpatterns followed
by one or more ellipses may occur only in subtemplates that are followed by
(at least) as many ellipses. These pattern variables are replaced in the output
by the input subforms to which they are bound, distributed as specified. If a
pattern variable is followed by more ellipses in the subtemplate than in
the associated subpattern, the input form is replicated as necessary. The
subtemplate must contain at least one pattern variable from a subpattern
followed by an ellipsis, and for at least one such pattern variable, the
subtemplate must be followed by exactly as many ellipses as the subpattern
in which the pattern variable appears.
bound-identifier=?
returns #t if given arguments are exactly the same object.
The bound-identifier=? procedure can be used for detecting duplicate
identifiers in a binding construct or for other preprocessing of a binding
construct that requires detecting instances of the bound identifiers.
free-identifier=?
procedure returns #t if given arguments are indicating the same bindings.
datum->syntax
procedure returns a syntax-object representation of
datum that contains the same contextual information as template-id,
with the effect that the syntax object behaves as if it were introduced into the
code when template-id was introduced.
The datum->syntax
procedure allows a transformer to "bend" lexical scoping
rules by creating implicit identifiers that behave as if they were present in the
input form, thus permitting the definition of macros that introduce visible
bindings for or references to identifiers that do not appear explicitly in the
input form. For example, the following defines a loop
expression that uses
this controlled form of identifier capture to bind the variable break to an escape
procedure within the loop body.
(define-syntax loop (lambda (x) (syntax-case x () [(k e ...) (with-syntax ([break (datum->syntax (syntax k) 'break)]) (syntax (call-with-current-continuation (lambda (break) (let f () e ... (f))))))]))) (let ((n 3) (ls '())) (loop (if (= n 0) (break ls)) (set! ls (cons 'a ls)) (set! n (- n 1))))=> (a a a)
gensym
in (sagittarius)
library.
with-syntax
form is used to bind pattern variables, just
as syntax-case
pattern. The
value of each expression is computed and destructured according to the
corresponding pattern, and pattern variables within the pattern are
bound as with syntax-case
to the corresponding portions of the value
within body.
quasisyntax
form is similar to syntax
, but it
allows parts of the quoted text to be evaluated, in a manner similar to the
operation of quasiquote
.
Within a quasisyntax
template, subforms of unsyntax
and
unsyntax-splicing
forms are evaluated, and everything else is treated
as ordinary template material, as with syntax
. The value of each
unsyntax
subform is inserted into the output in place of the unsyntax
form, while the value of each unsyntax-splicing
subform is spliced into
the surrounding list or vector structure. Uses of unsyntax
and
unsyntax-splicing
are valid only within quasisyntax
expressions.
A quasisyntax
expression may be nested, with each quasisyntax
introducing a new level of syntax quotation and each unsyntax
or
unsyntax-splicing
taking away a level of quotation. An expression nested
within n quasisyntax
expressions must be within n unsyntax
or
unsyntax-splicing
expressions to be evaluated.
syntax-violation
procedure raises an exception, reporting a syntax
violation. Who should describe the macro transformer that detected the
exception. The message argument should describe the violation. Form
should be the erroneous source syntax object or a datum value representing a form.
The optional subform argument should be a syntax object or datum value
representing a form that more precisely locates the violation.
(rnrs hashtables (6))
library provides a set of operations on
hashtables. A hashtable is a data structure that associates keys with
values. Any object can be used as a key, provided a hash function and a
suitable equivalence function is available. A hash function is a
procedure that maps keys to exact integer objects. It is the programmer's
responsibility to ensure that the hash function is compatible with the
equivalence function, which is a procedure that accepts two keys and returns
true if they are equivalent and #f otherwise. Standard hashtables for arbitrary
objects based on the eq?
and eqv?
predicates are provided. Also,
hash functions for arbitrary objects, strings, and symbols are provided.
This section uses the hashtable parameter name for arguments that must be
hashtables, and the key parameter name for arguments that must be
hashtable keys.
eq?
(make-eq-hashtable
) or eqv?
(make-eqv-hashtable
).
If optional argument k is given, it must be exact non-negative integer or
#f
. If it's #f
, then the procedure picks up default initial
capacity, otherwise the initial capacity of the hashtable is set to
approximately k elements.
If optional argument weakness is given, then it must be one of the
symbols key
, value
or both
, or #f
. If the value is
one of the symbols, then the procedure creates weak hashtable of given symbol's
weakness. If the symbol is key
, then entries whose keys are refered only
from this hashtable might be removed when garbage collection is
occurred. value
is for entry values. both
is for both.
make-hashtable
procedure returns a newly allocated mutable hashtable
using hash-function as the hash function and equiv as the
equivalence function used to compare keys.
If optional argument k and weakness are the same as
make-eq-hashtable
and make-eqv-hashtable
.
hashtable-ref
and hashtable-contains?
do
not make any difference fot the performance.
hashtable-update!
procedure applies proc to the value in
hashtable associated with key, or to default if
hashtable does not contain an association for key. The
hashtable is then changed to associate key with the value returned
by proc.
}
equal?
and symbols.
string=?
and string-ci=?
.
If the optional argument start and end is given, then the given
string will be substringed with start and end.
If the optional argument bound is given, it must be exact integer and hash
function will also use the given value.
(rnrs enums (6))
library for dealing with
enumerated values and sets of enumerated values. Enumerated values are represented
by ordinary symbols, while finite sets of enumerated values form a separate type,
known as the enumeration sets. The enumeration sets are further partitioned
into sets that share the same universe and enumeration type. These
universes and enumeration types are created by the make-enumeration
procedure. Each call to that procedure creates a new enumeration type.
make-enumeration
procedure creates a new enumeration type whose
universe consists of those symbols (in canonical order of their first appearance
in the list) and returns that universe as an enumeration set whose universe is
itself and whose enumeration type is the newly created enumeration type.
enum-set-member?
procedure returns #t if its first
argument is an element of its second argument, #f otherwise.
The enum-set-subset?
procedure returns #t if the universe of
enum-set1 is a subset of the universe of enum-set2 (considered as
sets of symbols) and every element of enum-set1 is a member of
enum-set2. It returns #f otherwise.
The enum-set=?
procedure returns #t if enum-set1 is a subset of
enum-set2 and vice versa, as determined by the enum-set-subset?
procedure. This implies that the universes of the two sets are equal as sets of
symbols, but does not imply that they are equal as enumeration types. Otherwise,
#f is returned.
enum-set-union
procedure returns the union of enum-set1 and
enum-set2.
The enum-set-intersection
procedure returns the intersection of
enum-set1 and enum-set2.
The enum-set-difference
procedure returns the difference of enum-set1
and enum-set2.
define-enumeration
form defines an enumeration type and
provides two macros for constructing its members and sets of its members.
A define-enumeration
form is a definition and can appear anywhere any
other definition can appear.
Type-name is an identifier that is bound as a syntactic keyword;
symbol ... are the symbols that comprise the universe of the enumeration
(in order).
(type-name symbol)
checks at macro-expansion time whether the
name of symbol is in the universe associated with type-name. If it is,
(type-name symbol)
is equivalent to symbol. It is a syntax
violation if it is not.
Constructor-syntax is an identifier that is bound to a macro that, given any
finite sequence of the symbols in the universe, possibly with duplicates, expands
into an expression that evaluates to the enumeration set of those symbols.
(constructor-syntax symbol ...)
checks at macro-expansion
time whether every symbol ... is in the universe associated with
type-name. It is a syntax violation if one or more is not. Otherwise
(constructor-syntax symbol ...)is equivalent to
((enum-set-constructor (constructor-syntax)) '(symbol ...)).
(rnrs eval (6))
library allows a program to create Scheme
expressions as data at run time and evaluate them.
environment
procedure. However on Sagittarius, environment can be
anything. This behaviour might be fixed in future.
environment
procedure returns an environment corresponding to import-spec.
set-car!
and set-cdr!
.string-set!
and string-fill!
.string-set!
procedure stores char in element k of string
and returns unspecified values.
&assertion
to be raised.
exact->inexact
.inexact
and exact
procedures.delay
construct is used together with the procedure
force
to implement lazy evaluation or call by need.
(delay expression)
returns an object called a promise which
at some point in the future may be asked (by the force
procedure) to
evaluate expression, and deliver the resulting value. The effect of expression
returning multiple values is unspecified.
force
procedure forces the value of promise. If no value has
been computed for the promise, then a value is computed and returned. The value
of the promise is cached (or "memoized") so that if it is forced a second time,
the previously computed value is returned.
eval
.
export
export-spec ...)import
import-set ...)begin
command-or-definition ...)include
filenames ...)include-ci
filenames ...)include-library-declarations
filenames ...)cond-expand
cond-expand-clause ...)export
and import
are the same as R6RS. And on R7RS renaming
export syntax is different from R6RS, however on Sagittarius both can be
accepted.
begin
starts the library contents. However it can appear more than once.
include
and include-ci
includes the files which are specified
filenames. filenames must be string. This resolves file path from
current loading file. If the library file is /usr/local/lib/lib1.scm, then
search path will be /usr/local/lib. It can also take absolute path.
include-ci
reads the file case insensitive.
cond-exnpand
is the same as builtin syntax cond-expand
. For more
detail, see Builtin Syntax.
* + - ... / < <= = => > >= abs and append apply assoc assq assv begin binary-port? boolean=? boolean? bytevector-copy bytevector-length bytevector-u8-ref bytevector-u8-set! bytevector? caar cadr call-with-current-continuation call-with-port call-with-values call/cc car case cdar cddr cdr ceiling char->integer char<=? char<? char=? char>=? char>? char? close-input-port close-output-port close-port complex? cond cons current-error-port current-input-port current-output-port define define-record-type define-syntax denominator do dynamic-wind else eof-object eof-object? eq? eqv? error even? exact exact-integer-sqrt exact? expt floor flush-output-port for-each gcd guard if inexact inexact? input-port? integer->char integer? lambda lcm length let let* let*-values let-values letrec letrec* list list->string list->vector list-ref list-tail list? make-bytevector make-string make-vector map max member memq memv min modulo negative? newline not null? number->string number? numerator odd? or output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient raise raise-continuable rational? rationalize read-char real? remainder reverse round set! set-car! set-cdr! string string->list string->number string->symbol string->utf8 string-append string-copy string-for-each string-length string-ref string-fill! string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol=? symbol? syntax-rules textual-port? truncate unless unquote unquote-splicing utf8->string values vector vector->list vector-fill! vector-for-each vector-length vector-map vector-ref vector-set! vector? when with-exception-handler write-char zero?This is defined in (sagittarius);
cond-expand
(converter init)
if converter
is given, otherwise init.
If the parameter object is applied without an argument, then it returns
the value associated with the parameter object.
If the parameter object is applied with an argument, then it changes the
associated value with the given value which may converted by converter
if the parameter object is created with converter.
parameterize
expression is used to change the
values returned by specified parameter objects during the evaluation of
body.include-ci
reads
files case insensitively.
lambda
expression are matched to the arguments in a procedure call.
/
returns two integers; the other procedures
return an integer. All the procedures compute a quotient nq and
remainder nr such that n1 = n2*nq + nr
.
for each of the division operators, there are three procedures defined as
follows;
(<operator>/ n1 n2)=> nq nr
(<operator>-quotient n1 n2)=> nq
(<operator>-remainder n1 n2)=> nr
nq:nr = n1 - n2*nq
. Each set of
operations uses a different choice of nq:
floor
: nq = [n1/n2]
truncate
: nq = truncate(n1/n2)
Examples;
(floor/ 5 2)=> 2 1
(floor/ -5 2)=> -3 1
(floor/ 5 -2)=> -3 -1
(floor/ -5 -2)=> 2 -1
(truncate/ 5 2)=> 2 1
(truncate/ -5 2)=> -2 -1
(truncate/ 5 -2)=> -2 1
(truncate/ -5 -2)=> 2 -1
(truncate/ -5.0 -2)=> 2.0 -1.0
&syntax
with syntax-violation
.
The macro is defined like this;
(define-syntax syntax-error (syntax-rules () ((_ msg args ...) (syntax-violation 'syntax-error msg (quote args ...)))))
consition?
.
irritants-condition?
. Otherwise #f.
message-condition?
. Otherwise #f.
i/o-read-error?
.port-ready?
.
\n
, \r
and \r\n
are considered end of line.
cond-expand
treas as true.
(rnrs base)
is that this procedure
inspect record fields as well. For example:
(import (rnrs)) (define-record-type (<pare> kons pare?) (fields (mutable a kar set-kar!) (mutable d kdr set-kdr!))) (let ((a (kons 'a 'b)) (b (kons 'a 'b))) (equal? a b))=> #f
(import (scheme base)) (define-record-type (<pare> kons pare?) (fields (mutable a kar set-kar!) (mutable d kdr set-kdr!))) (let ((a (kons 'a 'b)) (b (kons 'a 'b))) (equal? a b))=> #t
(rnrs base)
and these macros is
that these macro create scope. Thus the following is unbound variable error:
(import (scheme base)) (let-syntax () (define foo 'foo)) foo=> &undefined
case-lambda
syntax.
Exported macro is the same as R6RS;
case-lambda
char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-foldcase char-lower-case? char-numeric? char-upcase char-upper-case? char-whitespace? string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-downcase string-foldcase string-upcase
(digit-value #\1)=> 1
(digit-value #\x0664)=> 4
(digit-value #\x0EA6)=> #f
(digit-value #\xbc)=> 1/4
(digit-value #\xbf0)=> 10
angle imag-part magnitude make-polar make-rectangular real-part
caaaar caaadr caaar caadar caaddr caadr cadaar cadadr cadar caddar cadddr caddr cdaaar cdaadr cdaar cdadar cdaddr cdadr cddaar cddadr cddar cdddar cddddr cdddr
environment eval
call-with-input-file call-with-output-file delete-file file-exists? open-input-file open-output-file with-input-from-file with-output-to-file
acos asin atan cos exp finite? infinite? log nan? sin sqrt tan
delay force make-promise promise?
(delay-force expression)
is conceptually
similar to (delay (force expression))
, with the difference that
forcing the result of delay-force
will in effect result in a tail call
to (force expression)
, while forcing the result of
(delay (force expression))
might not.
command-line exit
read/ss
.interaction-environment
procedure.display
write/ss
and write
, respectively.
transcript-on
and transcript-off
are
not present. Note that the exact
and inexact
procedures
appear under their R5RS names inexact->exact
and
exact->inexact
respectively. However, if an implementation does
not provide a particular library such as the complex library, the
corresponding identifiers will not appear in this library either. This
library exports procedures for writing Scheme objects.
(srfi :1)
.
(srfi :133)
.
(srfi :132)
.
(srfi :113)
.
(srfi :14)
.
(srfi :125)
.
(srfi :116)
.
(srfi :101)
with the following exceptions:
make-list
is renamed to make-rlist
.
random-access-list->linear-access-list
is renamed to rlist->list
.
linear-access-list->random-access-list
is renamed to list->rlist
.
All other procedures are prefixed with r
. For example, pair?
exported from (srfi :101)
is rpair?
.
(srfi :134)
.
(srfi :135)
.
(srfi :158)
.
(srfi :127)
.
(srfi :41)
.
(srfi :111)
.
(srfi :117)
.
(srfi :124)
.
(srfi :128)
.
(srfi :141)
.
(srfi :143)
.
(srfi :144)
.
(srfi :146)
.
(srfi :146 hash)
.
(srfi :151)
.
(srfi :159)
.
(srfi :160 base)
.
(srfi :160 @)
. Where @
is one of
u8 s8 u16 s16 u32 s32 u64 s64 f32 f64 c64 c128
(rnrs bytevectors)
.
NOTE: The exporting names may conflicts with the ones exported from R7RS
libraries (e.g. bytevector-copy!
from (scheme base)
).
1
is instance of <integer>
class.
However CLOS has huge features and I don't have intension to implement all of
it.
This section does not describe CLOS itself.
slots ::= (slot ...) slot ::= (slot-name specifiers*) specifiers ::=Defines a new class. Slot specifiers::init-keyword
keyword |:init-value
value |:init-form
form |:reader
reader-function |:writer
writer-function
:init-keyword
make
procedure. Following code describes how to use:
(make <a-class> :slot-a 'slot-a-value)
<a-class>
has a slot which slot definition contains the keyword
:init-keyword
with the keyword :slot-a. The code initialises
an instance of the slot with given value slot-a-value.
:init-value
:init-form
:init-keyword
but this keyword takes expression which
will be evaluated at initialiation time.
:reader
slot-ref
procedure.
:writer
slot-set!
procedure.
:metaclass
.
NOTE: Current implementation does not support :allocation
keyword
by default. If you need it, see
(sagittarius mop allocation).
specifiers ::= (spec ... rest) spec ::= (argument-name class) | (argument-name) rest ::= '() | symbolAdds defined method to name generic. If the generic does not exist, this will create a new generic function implicitly.
equal?
is called.
Defines how user defined class should be compared.
compute-getter-and-setter
. This method should only
be used if users absolutely need to use accessor to access the target slots.
define
however the define-constant
binds
variable as a constant value and the compiler try to fold it if it is
constant value i.e. literal string, literal vector, literal number and so.
If the defined variable is being overwritten, the VM shows a warning
message on the standard error. If overwriten is forbidden by
#!no-overwite
or other directives, then compiler raises an error.
lambda
.
Expression must be an expression.
receive
binds values which are generated by expressions to
formals.
The expressions in body are evaluated sequentially in the extended
environment. The results of the last expression in the body are the values of
the receive
-expression.
cond-expand
resolves
platform dependencies such as C's #ifdef
preprocessor.
clauses must be one of these forms:
library
library-name) body ...)and
feature-identifier ...) body ...)or
feature-identifier ...) body ...)not
feature-identifier)library
form searches the given library-name and if it is found,
then compiles body.
and
, or
and not
are the same as usual syntax.
Users can check possible feature-identifiers via cond-features
procedure.
datum->syntax
, it doesn't require template identifier.free-identifier=?
. If the given
arguments are list or vector, then the procedure checks its elements.er-macro-transformer
returns explicit renaming macro transformer, so
you can write both hygine and non-hygine macro with it. For example:
(define-syntax loop (er-macro-transformer (lambda (form rename compare) (let ((body (cdr form))) `(,(rename 'call/cc) (,(rename 'lambda) (break) (,(rename 'let) ,(rename 'f) () ,@body (,(rename 'f))))))))) (let ((n 3) (ls '())) (loop (if (= n 0) (break ls)) (set! ls (cons 'a ls)) (set! n (- n 1))))=> (a a a)
datum->syntax
description. The basic of er-macro-transformer
is
the opposite way of the syntax-case
. The syntax-case
always makes
macro hygine, however the er-macro-transformer
can make macro hygine.
Moreover, if you do not use rename, it always makes it non-hygine.
+
, *
, -
and /
. The difference is
these procedures converts given arguments inexact number.x ^ -1 mod m
x ^ e mod m
&i/o
condition.
file-stat-ctime
procedure returns last change time of filename.
The file-stat-mtime
returns last modified time of filename.
The file-stat-atime
returns last accesse time of filename.
&i/o
.
If new-filename exists, it overwrite the existing file.
&i/o
.
current-directory
sets
current working directory to path and returns unspecified value.
make-eq-hashtable
and
make-eqv-hashtable
. It uses equal?
or string=?
as
comparing procedure, respectively.hashtable-keys
.hashtable-keys
and hashtable-values
are implemented with these procedures.
eq
, eqv
, equal
, string
and
general
.
key
, value
and both
. endianness
macro.
Write v to out as unsigned/signed 16/32 bit integer.endianness
macro.
Read a number from in as unsigned/signed 16/32.put-*
and get-*
have only 16 and 32 bit integers.
This is because benchmark told us there's not much difference between C and
Scheme implementation. We may add 64 bit integers and floting number
versions in future if there's enough demand.
read/ss
reads a datum from given port.
The write/ss
writes obj to given port.
These are the same as read
and write
procedure, but it can handle
circular list.
'~'
, and ends with some specific
characters. A format directive takes the corresponding arg and formats it. The
rest of string is copied to the output as is.
(format #f "the answer is ~a" 48)=> the anser is 48
'@'
and colon ':'
. One or both of them may modify the
behaviour of the format directive. Those flags must be placed immediately
before the directive character.
The following complete list of the supported directives. Either upper case or
lower case character can be used for the format directive; usually they have no
distinction, except noted.
display
. If an
integer mincol is given, it specifies the minimum number of characters to
be output; if the formatted result is shorter than mincol, a whitespace is
padded to the right (i.e. the result is left justified).
The colinc, minpad and padchar parameters control, if given,
further padding. A character padchar replaces the padding character for the
whitespace. If an integer minpad is given and greater than 0, at least
minpad padding character is used, regardless of the resulting width. If an
integer colinc is given, the padding character is added (after minpad) in
chunk of colinc characters, until the entire width exceeds mincol.
If atmark-flag '@'
is given, the format result is right
justified, i.e. padding is added to the left.
The maxcol parameter, if given, limits the maximum number of characters to
be written. If the length of formatted string exceeds maxcol, only
maxcol characters are written. If colon-flag is given as well and the
length of formatted string exceeds maxcol, maxcol - 4 characters
are written and a string " ..."
is attached after it.
(format #f "|~a|" "oops")=> |oops|
(format #f "|~10a|" "oops")=> |oops |
(format #f "|~10@a|" "oops")=> | oops|
(format #f "|~10,,,'*@a|" "oops")=> |******oops|
(format #f "|~,,,,10a|" '(abc def ghi jkl))=> |abc def gh|
(format #f "|~,,,,10:a|" '(abc def ghi jkl))=> |abc de ...|
write
. The
semantics of parameters and flags are the same as ~A directive.
(format #f "|~s|" "oops")=> |"oops"|
(format #f "|~10s|" "oops")=> |"oops" |
(format #f "|~10@s|" "oops")=> | "oops"|
(format #f "|~10,,,'*@s|" "oops")=> |****"oops"|
(format #f "|~d|" 12345)=> |12345|
(format #f "|~10d|" 12345)=> | 12345|
(format #f "|~10,'0d|" 12345)=> |0000012345|
'+'
is printed for the positive
argument.
If colon-flag is given, every intervalth digit of the result is grouped
and commachar is inserted between them. The default of commachar is
','
, and the default of interval is 3.
(format #f "|~:d|" 12345)=> |12,345|
(format #f "|~,,'_,4:d|" -12345678)=> |-1234_5678|
'X'
is used, upper case alphabets are used for the digits larger than 10.
If 'x'
is used, lower case alphabets are used. The semantics of
parameters and flags are the same as the ~D directive.
(format #f "~8,'0x" 259847592)=> 0f7cf5a8
(format #f "~8,'0X" 259847592)=> 0F7CF5A8
;; Assume read! is provided. (define user-port (make-custom-binary-input-port "my-port" read! #f #f)) (port-ready user-port)=> #t
(buffer-mode block)
or (buffer-mode line)
uses the buffered
port. This is useful when actual I/O is more expensive than memory access.
The buffer-mode must be a symbol the macro buffer-mode
can
return. If the buffer-mode
is none
, then the procedure does not
convert the given port.
If the keyword argument buffer is specified, it must be
a bytevector, then the converted buffered port uses specified bytevector
as its internal buffer. If the bytevector size is zero or literal bytevector
then &assertion
is raised.
ignore
, raise
or
replace
depending on a transcoder which uses this custom codec.
Check-bom? is boolean, if getc is being called first time, it is #t,
otherwise #f. Userdata is user defined data which is given when the codec
is created.
The basic process of getc is reading binary data from input-port and
converting the data to UCS4. Returning UCS4 must be integer and does not have to
be 4 byte.
Putc must take 4 arguments, output-port, char,
error-handling-mode and userdata. Output-port is binary output
port. Char is character object which needs to be converted from UCS4.
Error-handling-mode is symbol can be ignore
, raise
or
replace
depending on a transcoder which uses this custom codec.
Userdata is user defined data which is given when the codec is created.
The basic process of putc is converting given UCS4 charactner to target
encoding data and putting it to output-port as binary data.
For sample implementation, see sitelib/encoding directory. You can find some
custom codecs.
string<?
, string<=?
,
string>?
and string>=?
.
These can also be implemented as follows:
(define (symbol<? . syms) (apply string<? (map symbol->string syms)))However, this build-in version won't converts given symbols to strings.
':'
. It has almost the
same feature as symbol, however it can not be bounded with any values. The
keyword objects are self quoting so users don't have to put '
explicitly.
The keyword notation is *NOT* available on R6RS or R7RS reader mode. Thus
#!r6rs
or #!r7rs
directive and -r6
or -r7
command line option disable it.
&error
when keyword is not found in
list.
If fallback is given and the procedure could not find the keyword
from the list, the fallback will be return. Otherwise it raises
&error
.
(get-keyword :key '(a b c :key d))=> d
(get-keyword :key '(a b c d e))=> &error
(get-keyword :key '(a b c d e) 'fallback)=> &error
(get-keyword :key '(a b c d e f) 'fallback)=> fallback
weak-vector-ref
raise an &assertion
if k is
negative, or greater than or equal to the size of wvec. However, if an
optional argument fallback is given, it is returned for such case.
If the element has been garbage collected, this procedure returns fallback
if it is given, #f otherwise.
&assertion
if k is negative or greater than or equal to
the size of wvec.
eq?
and eqv?
,
respectively.
The keyword argument init-size specifies the initial size of the
weak hashtable.
The kwyword argument weakness specifies the place where the weak pointer
is. This must be one of the key
, value
and both
. If the
key
is specified, then weak hashtable's weak pointer will be the key
so is value
. If the both
is specified, then it will be both.
The keyword argument default specifies the default value when the entry
is garbage collected. If this is not spceified, then undefined value will be
used.
(integer->bytevector #x12345678 5)=> #vu8(#x00 #x12 #x34 #x56 #x78)
(integer->bytevector #x12345678 3)=> #vu8(#x34 #x56 #x78)
(apply bytevector-append list-of-bytevectors)
(cons (cons obj1 obj2) obj3)
. Useful to
put an entry at the head of an associative list.
(vector-copy '#(0 1 2 3 4) 1 4)=> #(1 2 3)
(vector-copy '#(0 1 2 3 4) 4 6 #f)=> #(4 #f)
(vector-copy '#() 0 2 #t)=> #(#t #t)
(vector-append '#(1 2) '#(a b) '#(5))=> #(1 2 a b 5)
(apply vector-append list-of-vectors)
index
#f
.
This is the default behaviour.
before
#f
if
item is not found.
after
#f
if
item is not found.
before*
(values #f #f)
.
after*
(values #f #f)
.
both
(values #f #f)
.
(apply string-append list-of-strings)
"abc"
)string->istring
#t
, then given path is
appended to the current loading path list, otherwise prepend to the list.
#t
, then given suffix is
appended to the current suffix list, otherwise prepend to the list.
The suffix should contain .
as well.
uname(2)
.
On Windows environment, this is the result of couple of Win32 API calls
and formatted to look like the result of uname(2)
.
get-process-times
returns value of _SC_CLK_TCK
, and
get-thread-times
returns 1000000 (on OSX), 1000000000 (on other POSIX
environments which have pthread_getcpuclockid
), or _SC_CLK_TCK
(on other POSIX environments which don't have pthread_getcpuclockid
). So
users must not assume the value is one of them and calculate CPU second with
assumed value.
taskset(1)
.
This procedure returns static value initialised during initialisation of
Sagittarius process. Thus, if the process is restricted after its
initialisation by taskset(1)
, for example the environment has 4 CPUs
but restricted to 1, then this process, however, returns 4.
time
macro(define-macro name (lambda formals body ...))
let-optionals*
where you have only one
optional argument. Given the optional argument list restargs, this macro
returns the value of optional argument if one is given, or the result of
default otherwise.
If latter form is used, test must be procedure which takes one argument
and it will be called to test the given argument. If the test failed, it raises
&error
condition.
Default is not evaluated unless restargs is an empty list.
(symbol expr)If the restrag contains keyword which has the same name as symbol, binds symbol to the corresponding value. If such a keyword doesn't appear in restarg, binds symbol to the result of expr.
(symbol keyword expr)If the restarg contains keyword keyword, binds symbol to the corresponding value. If such a keyword doesn't appear in restarg, binds symbol to the result of expr. The default value expr is only evaluated when the keyword is not given to the restarg. If you use the first form,
let-keyword
raises &error
condition
when restarg contains a keyword argument that is not listed in
var-specs. When you want to allow keyword arguments other than listed in
var-specs, use the second form.
In the second form, restvar must be either a symbol or #f. If it is a
symbol, it is bound to a list of keyword arguments that are not processed by
var-specs. If it is #f, such keyword arguments are just ignored.
(define (proc x . options) (let-keywords options ((a 'a) (b :beta 'b) (c 'c) . rest) (list x a b c rest)))
(proc 0)=> (0 a b c ())
(proc 0 :a 1)=> (0 1 b c ())
(proc 0 :beta 1)=> (0 a 1 c ())
(proc 0 :beta 1 :c 3 :unknown 4)=> (0 a 1 3 (unknown 4))
let-keywords
, but the binding is done in the order of
var-specs. So each expr can refer to the variables bound by
preceding var-specs.
These let-keywords and let-keywords* are originally from Gauche.
(let ((var expr)) body ...)
(let ((var expr)) body ... var)
(dotimes (variable limit result) body ...)=>
(do ((tlimit limit) (variable 0 (+ variable 1))) ((>= variable tlimit) result) body ...)
(dolist (variable lexpr result) body ...)=>
(begin (for-each (lambda (variable) body ...) lexpr) (let ((variable '())) result))
set!
. The result will be the same as set!
.
&assertion
is raised.
The proc should be the procedure name which uses this macro and is for
debugging purpose.
syntax->datum
.with-syntax
, the only difference is
that this macro can refer previous pattern of p as if let*
can.
This can reduce nest level when users need to write multiple
with-syntax
to refer bound syntax object.
lambda
.(lambda (c) body ...)
. Where c
can be any character of lower case of ASCII alphabet.
(map (^z (* z z)) '(1 2 3 4 5))=> (1 4 9 16 25)
(lambda c body ...)
. Where c
can be any character of lower case of ASCII alphabet.
(map (^z* z*) '(1 2 3 4 5))=> ((1) (2) (3) (4) (5))
;; Scheme file ;; load shared library (on Windows the extension might be '.dll') ;; On Unix like environment, the shared library must be full path or ;; located in the same directory as the script. ;; On Windows it can be on PATH environment variable as well. (define so-library (open-shared-library "my-quick-sort.so")) (define quick-sort (c-function so-library ;; shared library void ;; return type quicksort ;; exported symbol ;; argument types ;; if you need pass a callback procedure, 'callback' mark needs to ;; be passed to the arguments list (void* size_t size_t callback))) (let ((array (u8-list->bytevector '(9 3 7 5 2 6 1 4 8))) ;; callback procedure (compare (c-callback int ;; return type (void* void*) ;; argument types (lambda (a b) (- (pointer-ref-c-uint8 x 0) (pointer-ref-c-uint8 y 0)))))) ;; call c function. all loaded c functions are treated the same as ;; usual procedures. (quick-sort array (bytevector-length array) 1 compare) ;; release callback procedure. ;; NOTE: callback won't be GCed so users need to release it manually (free-c-callback compare) array) ;; Close shared library. (close-shared-library so-library) ;; End of Scheme file /* C file, must be compiled as a shared library and named 'my-quick-sort.so' */ #include <stdlib.h> #include <string.h> #ifdef _MSC_VER # define EXPORT __declspec(dllexport) #else # define EXPORT #endif static void quicksort_(uintptr_t base,const size_t num,const size_t size, void *temp,int (*compare)(const void *,const void *)) { size_t pivot = 0,first2last = 0,last2first = num-1; while(pivot+1 != num && !compare(base+size*pivot,base+size*(pivot+1))){ pivot++; } if(pivot+1 == num){ return; } if(0 > compare(base+size*pivot,base+size*(pivot+1))){ pivot++; } while(first2last < last2first){ while(0 < compare(base+size*pivot,base+size*first2last) && first2last != num-1){ first2last++; } while(0 >= compare(base+size*pivot,base+size*last2first) && last2first){ last2first--; } if(first2last < last2first){ if(pivot == first2last || pivot == last2first){ pivot = pivot^last2first^first2last; } memcpy(temp,base+size*first2last,size); memcpy(base+size*first2last,base+size*last2first,size); memcpy(base+size*last2first,temp,size); } } quicksort_(base,first2last,size,temp,compare); quicksort_(base+size*first2last,num-first2last,size,temp,compare); } EXPORT int quicksort(void *base, const size_t num, const size_t size, int (*compare)(const void *, const void *)) { void *temp = malloc(size); if(!temp){ return -1; } quicksort_((uintptr_t)base,num,size,temp,compare); free(temp); return 0; }=> #vu8(1 2 3 4 5 6 7 8 9)
open-shared-library
is depending on the
platform, for example if your platform is POSIX envirionment then it will use
dlopen
. So the resolving the file depends on it. If you know the
absolute path of the shared library, then it's always better to use it.
If then internal process of the procedure failed and raise is #f then it
returns NULL pointer, if raise is #t then it raises an error.
".dll"
in Windows, ".so"
in Linux or Unix.
void bool char short int long long-long unsigned-short unsigned-int unsigned-long unsigned-long-long intptr_t uintptr_t float double void* char* wchar_t* int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_tThe return value will be converted corresponding Scheme value. Following describes the conversion;
bool
char*
wchar_t*
char
short int long long-long
unsigned-short unsigned-int unsigned-long unsigned-long-long
intptr_t uintptr_t
int8_t int16_t int32_t int64_t
uint8_t uint16_t uint32_t uint64_t
float double
void*
char
returns a Scheme integer not Scheme character.
name must be a symbol indicating a exported C function name.
argument-types must be zero or more followings;
bool char short int long long-long unsigned-short unsigned-int unsigned-long unsigned-long-long size_t void* char* wchar_t* float double int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t callback ___When the C function is called, given Scheme arguments will be converted to corresponding C types. Following describes the conversion;
bool
char short int long long-long unsigned-short
int8_t int16_t int32_t uint8_t uint16_t
unsigned-int unsigned-long uint32_t size_t
int64_t long-long
uint64_t unsigned-long-long
float
double
void* char*
void*
and char*
are actually treated the same, internally.
The conversion will be like this;
wchar_t*
callback
___
is for variable length argument and it must be the last position
of the argument type list, otherwise it raises an error.
c-function
macro. The arguments are the same as c-function
,
only argument-types must be a list of types.
(c-func (address pointer))This is equivalent of following C code;
c_func(&pointer)pointer can be a pointer object or a bytevector. If the second form is used, then the passing address is offset of offset. It is user's responsibility to make sure the given pointer has enough space when offset is passed. If the pointer is a bytevector and offset is more than the bytevector size, then an error is signaled.
c-function
's
return-type.
argument-types must be zero or following;
bool char short int long long-long intptr_t unsigned-char unsigned-short unsigned-int unsigned-long-long uintptr_t int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t int64_t float double size_t void*The conversion of C to Scheme is the same as
c-function
's
return-type.
NOTE: if the content of void*
won't be copied, thus if you modify it in
the callback procedure, corresponding C function will get affected.
NOTE: callback doesn't support char*
nor wchar_t*
. It is because
the conversion loses original pointer address and you might not want it. So
it is users responsibility to handle it.
proc must be a procedure takes the same number of arguments as
argument-types list.
Created callbacks are stored intarnal static storage to avoid to get GCed.
This is because C functions which accept callback may hold the given callback
in their storage which could be outside of Sagittarius GC root. So it is
users' responsibility to release created callback to avoid memory leak. To
release callbacks, you need to use c-callback
macro. The arguments are the same as c-callback
,
only argument-types must be a list of types.
(integer->pointer 0)=> #<pointer 0x0>
&assertion
.
&assertion
.
&assertion
.
pointer->object
.
Converts Scheme object to pointer and pointer to Scheme object respectively.
The operations are useful to pass Scheme object to callbacks and restore
it.
void* deref(void **pointer, int offset) { return pointer[offset]; }If NULL pointer is given, it raises
&assertion
.
memset(3)
.
NOTE: the fill will be converted to an unsigned char by the
memset(3)
.
The allocated memory will be GCed.
malloc
.
The allocated memory won't be GCed. So releasing the memory is users'
responsibility.
address
,
you might break some codes.
int8 int16 int32 int64
uint8 uint16 uint32 uint64
char wchar short int long long-long
unsigned-char unsigned-short unsigned-int unsigned-long unsigned-long-long
intptr uintptr
float double
pointer
NOTE: if the type is flonum
or double
, then it returns
Scheme flonum
NOTE: if the type is pointer
, then it returns Scheme FFI pointer.
pointer-ref-c-type
The type conversion is the same as c-function
's return-type.
There is no direct procedures to handle C arrays. Following is an example
of how to handle array of pointers;
(import (rnrs) (sagittarius ffi)) (define (string-vector->c-array sv) (let ((c-array (allocate-pointer (* (vector-length sv) size-of-void*)))) (do ((i 0 (+ i 1))) ((= i (vector-length sv)) c-array) ;; pointer-set-c-pointer! handles Scheme string (converts to UTF-8) ;; If you need other encoding, then you need to write other conversion ;; procedure. (pointer-set-c-pointer! c-array (* i size-of-void*) (vector-ref sv i))))) ;; how to use (let ((p (string-vector->c-array #("abc" "def" "ghijklmn")))) (do ((i 0 (+ i 1))) ((= i 3)) ;; deref handles pointer offset. ;; it can be also (pointer-ref-c-pointer p (* i size-of-void*)) (print (pointer->string (deref p i)))))Following is an example for Scheme string to UTF-16 bytevector;
(import (rnrs) (sagittarius ffi)) ;; Converts to UTF16 big endian (on little endian environment) (define (string->c-string s) (let* ((bv (string->utf16 s (endianness big))) ;; add extra 2 bytes for null terminated string (p (allocate-pointer (+ (bytevector-length bv) 2)))) (do ((i 0 (+ i 2))) ((= i (bytevector-length bv)) p) ;; pointer-set-c-uint16! uses native endianness to set the value ;; so this is platform dependent code. (pointer-set-c-uint16! p i (bytevector-u16-ref bv i (endianness little))))))
size-of-void*
bytes.
Sets the pointer value. This is useful to reuse the existing pointer object.
CAUTION: this operation is really dangerous so be aware of it!
(type name) (typename must be a symbol. If the second form is used, thenarray
size name) (struct
struct-name name) (bit-field
type (name bit) ...) (bit-field
(type endian) (name bit) ...)
alignment
is an auxiliary syntax
and n must be an integer which must be either negative number or
one of 1
, 2
, 4
, 8
, or 16
. This form
specifies the alignemtn of the struct. If the n is negative number,
then it uses platform default alignment, if it's one of the above number,
then the alignment is according to the given number.
The first form is the simple C type form. type must be a symbol and the
same as one of the c-function
's return-types or callback
.
Following describes the concrete example and the equivalent C structure:
(define-c-struct st (int foo) (callback fn)) #| struct st { int foo; void* fn; /* function pointer */ }; |#The second form is defining C type array with size. Following describes the concrete example and the equivalent C structure:
(define-c-struct st (int array 10 foo)) #| struct st { int foo[10]; }; |#The third form is defining internal structure. Following describes the concrete example and the equivalent C structure:
(define-c-struct st1 (int array 10 foo)) (define-c-struct st2 (struct st1 st) (int bar)) #| struct st1 { int foo[10]; }; struct st2 { struct st1 st; int bar; }; |#So far, we don't support direct internal structure so users always need to extract internal structures. The forth and fifth forms are bit fields. type must be an integer type such as
unsigned-int
. If the given type is not an integer,
then &assertion
is raised.
Following describes the concrete example and the equivalent C structure:
(define-c-struct st1 (bit-field unsigned-int (a 10) (b 20))) #| struct st1 { unsigned int a : 10; unsigned int b : 20; }; |#If the fifth form is used, then endian must be an identifier which has valid name for
endianness
macro. Then the created structure packs
the value according to the given endian.
If the total amount of bits is greater than given type, then
&assertion
is raised.
NOTE: Even though, this can accept signed integer the returning value would
not be signed. It is safe to specify unsigned type.
The macro also defines accessors for the c-struct. Following naming rules are
applied;
size-of-foo
.
define-c-struct
.
Returns the size of given struct.
define-c-struct
macro.
The optional argument inner-member-names can be passed to get inner
struct values.
Following describes how it works.
(define-c-struct in (int i) (char c)) (define-c-struct out (int i) (struct in in0)) (define out (allocate-c-struct out)) (out-i-set! out 100 'i) ;; -> unspecified (out-in0-set! out 200 'i) ;; -> unspecified (out-i-ref out) ;; -> 100 (out-in0-ref out 'i) ;; -> 200 (out-in0-ref out) ;; -> pointer object (indicating the inner struct address)
define-c-struct
.
name must be a symbol and struct has the same member.
pointer should be a pointer allocated by allocate-c-struct
with
struct.
Returns a member name's value of struct from pointer.
define-c-struct
.
name must be a symbol and struct has the same member.
pointer should be a pointer allocated by allocate-c-struct
with
struct.
Sets value to pointer offset of member name of struct.
() ((The first for defines nothing. If the rest of form is used and rest is not null, then it will recursively define. The second form's*
new-p) rest ...) ((s*
new-sp) rest ...) (new rest ...)
*
defines new-p as void*
.
The third form's s*
defines new-sp as char*
.
The forth form defines new as original.
Following example describes how to will be expanded approximately.
(define-c-typedef char (* char_ptr) byte (s* string)) => (begin (define char_ptr void*) (define byte char) (define string char*) )
bool char short int long long-long unsigned-short unsigned-int unsigned-long unsigned-long-long intptr_t uintptr_t size_t float double int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t void*The values are platform dependent.
tail (1)
like script shows how it works:
(import (rnrs) (getopt) (sagittarius filewatch) (prefix (binary io) binary:)) (define (tail file offset) (define watcher (make-filesystem-watcher)) (define in (open-file-input-port file)) ;; dump contents to stdout (define (dump) (let loop () (let ((line (binary:get-line in))) (unless (eof-object? line) (put-bytevector (standard-output-port) line) (put-bytevector (standard-output-port) #vu8(10)) (loop))))) (define size (file-size-in-bytes file)) ;; move port position if the size if more than offset (when (> size offset) (set-port-position! in (- size offset))) ;; dump first (dump) ;; add path to file watcher (filesystem-watcher-add-path! watcher file '(modify) (lambda (path event) (dump))) ;; monitor on foreground. (filesystem-watcher-start-monitoring! watcher :background #f)) ;; this tail is not line oriented ;; it shows tail of the file from the given offset. (define (main args) (with-args (cdr args) ((offset (#\o "offset") #t "1024") . rest) (tail (car rest) (string->number offset))))
access
modify
delete
move
attribute
accessed
modified
deleted
moved
attribute
&assertion
.
&assertion
.
filesystem-watcher-stop-monitoring!
.
inotify (7)
and
poll (2)
. If users add too many paths, then it may reach the
maximum number of watch descriptor.
The IN_MOVED_FROM
and IN_MOVED_TO
flags are passed as
moved
. So it is users responsibility to detect which file is
moved from and which file is moved to.
kqueue (2)
. This
implementation contains 3 major issues. Possibility of number of file
descriptor explosion, not access
flag support, and no support of
directory monitoring.
The kqueue
requires file descriptor per monitoring path. Thus if
the number of paths is large, then it reaches the maxinum number of file
descriptors. (NB: kern.maxfiles
on FreeBSD).
kqueue
doesn't support path access monitoring (e.g. IN_ACCESS
on inotify
). So it is impossible to monitor file access.
Current implementation of (sagittarius filewatch)
using kqueue
doesn't allow users to monitor directory. This is because by default,
kqueue
doesn't provide facility to detect which file is added.
To do it, we need manual management. To keep our code as simple as possible,
we decided not to do it for now. This decision may be changed if there's
enough demands.
kqueue
, thus the
same limitation as BSD Unix is applied.
access
flag may or may not work on
Windows depending on the configuration of the platform.
Due to the lack of deletion detect, delete
and move
work the
same. Thus the monitoring handler may get both deleted
and moved
even though it's only specified delete
or move
.
(define (call-with-input-string str proc) (proc (open-input-string str))) (define (call-with-output-string proc) (let ((port (open-output-string))) (proc port) (get-output-string port))) (define (with-input-from-string str thunk) (with-input-from-port (open-input-string str) thunk)) (define (with-output-to-string thunk) (let ((port (open-output-string))) (with-output-to-port port thunk) (get-output-string port)))
buffered-port
and transcoded-port
.;; example for input port
(import (rnrs) (sagittarius io) (clos user))
;; make a custom binary input port with 'read slot
(get-u8 (make <custom-binary-input-port>
:read (lambda (bv start count)
(bytevector-u8-set! bv start 1)
1)))
;; example for output port
(import (rnrs) (sagittarius io) (clos user))
;; user defined custom binary output port
(define-class <my-port> (<custom-binary-output-port>)
;; this port has own buffer
((buffer :init-form (make-bytevector 5 0))))
;; create the port
(let ((out (make <my-port>)))
;; set 'write slot
(slot-set! out 'write
(lambda (bv start count)
;; just get the first element of given bytevector
;; and set it to own buffer
(bytevector-copy! bv start (slot-ref out 'buffer) 0 count)
count))
;;
(put-bytevector out #vu8(1 2 3 4 5))
(slot-ref out 'buffer))
;; -> #vu8(1 0 0 0 0)
position
procedure must accept 0 argument. The procedure should
return the position of the port.
set-position
procedure must accept 2 argument, position
andwhence. Whence shall be a symbol of begin
,
current
or end
. The procedure should set the position
of the port according to the given whence and position.
read
procedure must accept 3 argument. bv or string,
start and count. The first argument is decided by the port
type. If the port is binary port, then bytevector bv is passed.
If the port is textual port, then string string is passed.
The procedure should fill given bv or string in count
data elements starting start. And return number of data filled.
write
procedure must accept 3 argument. bv or string,
start and count. The first argument is decided by the port
type. If the port is binary port, then bytevector bv is passed.
If the port is textual port, then string string is passed.
The procedure should retrieve data from given bv or string
upto count data elements starting start. And return number
of data read.
ready
procedure must accept 0 argument. The procedure should
return true value if the port is ready to read. Otherwise #f.
flush
procedure must accept 0 argument. The procedure should
flush the port.
close
procedure must accept 0 argument. The procedure should
close the port.
If the creating port is input port, then read
must be set before
any port operation. If the creating port is output port, then write
must be set before any port operation. Other slots are optional.
:allocation
option for define-class
.:allocation
option for
class slot definition, respectively.
The meta class must be used with :metaclass
option of
define-class
.
The mixin class must be a parent class.
Currently, we only support :instance
and :class
keywords.
The following code is the whole definition of this classes.
(define-class <allocation-meta> (<class>) ()) (define-method compute-getter-and-setter ((class <allocation-meta>) slot) (cond ((slot-definition-option slot :allocation :instance) => (lambda (type) (case type ((:instance) '()) ((:class) (let* ((init-value (slot-definition-option slot :init-value #f)) (init-thunk (slot-definition-option slot :init-thunk #f)) (def (if init-thunk (init-thunk) init-value))) (list (lambda (o) def) (lambda (o v) (set! def v))))) (else (assertion-violation '<allocation-meta> "unknown :allocation type" type))))) (else (call-next-method)))) (define-class <allocation-mixin> () () :metaclass <allocation-meta>)
:validator
and observer
options for
define-class
.:validator
is for before set the value to the slot so that user can check
the value if it's correct or not.
:observer
is for after set the value to the slot so that user can check
which value is set to the slot.
(import (clos user) (sagittarius mop eql)) (define-generic eql-fact :class <eql-specializable-generic>) (define-method eql-fact ((n (eql 0))) 1) (define-method eql-fact ((n <integer>)) (* n (eql-fact (- n 1)))) (eql-fact 10)=> 3628800
<generic>
.
To use eql specializer, generic functions must have this class as a metaclass.
slot-ref
.
Following classes are specialised by default.
<hashtable>
uses hashtable-ref
<list>
uses list-ref
<string>
uses string-ref
<vector>
uses vector-ref
string->number
as a
conversion procedure.
If the given object is character, it uses char->integer
as a
conversion procedure.
run
procedure invokes name process and waits until it ends.
Then returns process' exit status.
The call
procedure invokes name process and continue the Scheme
process, so it does not wait the called process. Then returns process object.
If you need to finish the process, make sure you call the process-wait
procedure described below.
Both procedures' output will be redirects current-output-port
and
current-error-port
. If you need to redirect it other place use
create-process
described below.
create-process
procedure creates and invokes a process indicated
name. Keyword arguments decide how to invoke and where to redirect the
outputs.
If stdout is #f or non output-port and call? is #f then
create-process
raises &assertion
.
stdout keyword argument indicates the port where to redirect the standard
output of the process. This can be either binary output port or textual output
port.
stderr keyword argument indicates the port where to redirect the standard
error of the process. This can be either binary output port or textual output
port. If this argument is #f, then stdout will be used.
call? keyword argument decides the default behaviour. If this is #t and
reader is not a procedure, then the create-process
uses
async-process-read
. If this is #f and reader is not a procedure,
then it uses sync-process-read
. If reader is provided, then it
uses given reader.
reader keyword argument must be procedure which takes 4 arguments,
process object, redirection of standard output and error, and transcoder
respectively. This procedure decides how to handle the output.
Note: on Windows, both standard output end error has limitation. So if you
replace the default behaviour, make sure you must read the output from the
process, otherwise it can cause deat lock.
transcoder keyword argument must be transcoder or #f. This can be used in
the procedure which specified reader keyword argument.
The procedure create-process
creates a process and call it. The
returning value is depending on the above keyword parameters. If reader
and stdout is provided, then the result value is the value returned from
reader procedure. Otherwise the created process object.
call
described above.
#f
.
NOTE: The exit status are platform dependent. On Windows, the value will be
32 bit integer. On POSIX, the value will be 8 bit unsigned integer.
NOTE: On POSIX environment, timeout only works if the given
process is created by make-process
related procedures. If the
process is created by pid->process
, then it raises an error with
ECHILD
.
process-kill
is called, then returning value is its status code. Otherwise -1.
If the keyword argument children? is given and if it's true value, then
the procedure kills the child processes. The process of killing child processes
is not the same between Windows and POSIX. On Windows, the process seeks all
possible child processes. On POSIX, it simply calls killpg (2)
.
GetExitCodeProcess
which means
if the process returns STILL_ACTIVE(259)
, then this procedure
return #t even if the process itself is already terminated.
On POSIX, the procedure uses kill (2)
sending 0 to check the
existance of the process.
(sagittarius process)
provides shared memory for
simple IPC.
no-create
is specified, and there is
no shared memory with given name, then &i/o-file-does-not-exist
is raised. If no-truncate
is specified, then the created shared
memory is intact, otherwise it is truncted.
shared-memory->bytevector
will be 0 length bytevector.
(sagittarius threads)
.
;;#<(sagittarius regex)> ;; this imports only reader macros ;; This form is only for backward compatibility ;; portable way for other R6RS implementation's reader. #!read-macro=sagittarius/regex (import (sagittarius regex)) ;; usual import for procedures #/regex/i ;; (sagittarius regex) defines #/regex/ form ;; reader macro in it. it converts it ;; (comple-regex "regex" CASE-INSENSITIVE)Writing reader macro on toplevel
(import (rnrs) (sagittarius reader)) (set-macro-character #\$ (lambda (port c) (error '$-reader "invliad close paren appeared"))) (set-macro-character #\! (lambda (port c) (read-delimited-list #\$ port))) !define test !lambda !$ !display "hello reader macro"$$$ !test$ ;; prints "hello reader macro"Writing reader macro in library and export it
#!compatible ;; make sure Sagittarius can read keyword (library (reader macro test) ;; :export-reader-macro keyword must be in export clause (export :export-reader-macro) (import (rnrs) (sagittarius reader)) (define-reader-macro $-reader #\$ (lambda (port c) (error '$-reader "unexpected close paren appeared"))) (define-reader-macro !-reader #\! (lambda (port c) (read-delimited-list #\$ port))) ) #!read-macro=reader/macro/test ;; imports reader macro !define test !lambda !$ !display "hello reader macro"$$$ !test$ ;; prints "hello reader macro"If you need to use reader macro in your library code, you need to define it outside of the library. The library syntax is just one huge list so Sagittarius can not execute the definition of reader macro inside during reading it.
define-reader-macro
macro associates char and proc as a
reader macro. Once it is associated and Sagittarius' reader reads it, then
dispatches to the proc with 2 arguments.
If non-term? argument is given and not #f, the char is marked as
non terminated character. So reader reads as one identifier even it it contains
the given char in it.
The first form is a convenient form. Users can write a reader macro without
explicitly writing lambda
. The form is expanded to like this:
(define-reader-macro #\$ ($-reader args ...) body ...) ;; -> (define-reader-macro $-reader #\$ (lambda (args ...) body ...))Note: the name is only for error message. It does not affect anything.
define-dispatch-macro
creates macro dispatch macro character char
if there is not dispatch macro yet, and associates subchar and proc
as a reader macro.
If non-term? argument is given and not #f, the char is marked as non
terminated character. So reader reads as one identifier even it it contains the
given char in it.
Note: the name is only for error message. It does not affect anything.
Macro character | Terminated | Explanation |
---|---|---|
#\( | #t | Reads a list until reader reads #\). |
#\[ | #t | Reads a list until reader reads #\]. |
#\) | #t | Raises read error. |
#\] | #t | Raises read error. |
#\| | #t | Reads an escaped symbol until reader reads #\|. |
#\" | #t | Reads a string until reader reads #\". |
#\' | #t | Reads a symbol until reader reads delimited character. |
#\; | #t | Discards read characters until reader reads a linefeed. |
#\` | #t | Reads a next expression and returns (quasiquote expr) |
#\, | #t | Check next character if it is @ and reads a next expression.
Returns (unquote-splicing expr) if next character was
@ , otherwise (unquote expr) |
#\: | #f | Only compatible mode. Reads a next expression and returns a keyword. |
#\# | #t(R6RS mode) | Dispatch macro character. |
Sub character | Explanation |
---|---|
#\' | Reads a next expression and returns (syntax expr) . |
#\` | Reads a next expression and returns (quasisyntax expr) |
#\, | Check next character if it is @ and reads a next expression.
Returns (unsyntax-splicing expr) if next character was
@ , otherwise (unsyntax expr) |
#\! | Reads next expression and set flags described below.
|
#\v | Checks if the next 2 characters are u and 8 and reads
a bytevector. |
#\u | Only compatible mode. Checks if the next character is 8 and reads
a bytevector. |
#\t and #\T | Returns #t. |
#\f and #\F | Returns #f. |
#\b and #\B | Reads a binary number. |
#\o and #\O | Reads a octet number. |
#\d and #\D | Reads a decimal number. |
#\x and #\X | Reads a hex number. |
#\i and #\I | Reads a inexact number. |
#\e and #\E | Reads a exact number. |
#\( | Reads a next list and convert it to a vector. |
#\; | Reads a next expression and discards it. |
#\| | Discards the following characters until reader reads |# |
#\\ | Reads a character. |
#\= | Starts reading SRFI-38 style shared object. |
#\# | Refers SRFI-38 style shared object. |
#\< | Reads expressions until '>' and imports reader macro from it. Note: if expressions contains symbol, which is illegal library name, at the end #<-reader can not detect the '>' because '>' can be symbol. So the error message might be a strange one. |
#!
. Following describes details of those modes;
no-overwrite
flag. With this mode, keywords are read as
symbols; for example, :key
is just a symbol and users can not use
extended lambda
syntax.
no-overwrite
flag.
#< (...) >
form and let reader
read above hash-bang, the read table will be reset. So following code will raise
a read error;
#!read-macro=sagittarius/regex #!r6rs #/regular expression/ ;; <- &lexical
#!reader=srfi/:49 define fac n if (zero? n) 1 * n fac (- n 1) (print (fac 10))
#!reader=
specifies which reader will be used. For this example, it will
use the one defined in (srfi :49)
library. For compatibility of the other
Scheme implementation, we chose not to use the library name itself but a bit
converted name.
(srfi :49)
, first remove all parentheses or brackets then replace spaces
to /
.
define
. However if you use the first form
then expr must be lambda
and it accept one argument.
The defined reader will be used on read time, so it needs to return valid
expression as a return value of the reader.
NOTE: Only one reader can be defined in one library. If you define more than
once the later one will be used.
:export-reader
keyword to the library export clause.
;; For Perl like (cond ((looking-at (regex "^hello\\s*(.+)") "hello world!") => (lambda (m) (m 1))))=> world!
;; For Java like (cond ((matches (regex "(\\w+?)\\s*(.+)") "123hello world!")) ;; this won't match (else "incovenient eh?"))The
matches
procedure is total match, so it ignores boundary matcher
'^'
and '$'
. The looking-at
procedure is partial match, so
it works as if perlre.
Construct | Matches |
---|---|
Characters | |
x
| The character x |
\\
| The backslash character |
\0n
| The character with octal value 0n (0 <= n <= 7) |
\0nn
| The character with octal value 0nn (0 <= n <= 7) |
\0mnn
| The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7) |
\xhh
| The character with hexadecimal value 0xhh |
\uhhhh
| The character with hexadecimal value 0xhhhh |
\Uhhhhhhhh
| The character with hexadecimal value 0xhhhhhhhh. If the value exceed the maxinum fixnum value it rases an error. |
\t
| The tab character ('\u0009') |
\n
| The newline (line feed) character ('\u000A') |
\r
| The carriage-return character ('\u000D') |
\f
| The form-feed character ('\u000C') |
\a
| The alert (bell) character ('\u0007') |
\e
| The escape character ('\u001B') |
\cx
| The control character corresponding to x |
Character classes | |
[abc]
| a, b, or c (simple class) |
[^abc]
| Any character except a, b, or c (negation) |
[a-zA-Z]
| a through z or A through Z, inclusive (range) |
[a-d[m-p]]
| a through d, or m through p: [a-dm-p] (union) |
[a-z&&[def]]
| d, e, or f (intersection) |
[a-z&&[^bc]]
| a through z, except for b and c: [ad-z] (subtraction) |
[a-z&&[^m-p]]
| a through z, and not m through p: [a-lq-z](subtraction) |
Predefined character classes | |
.
| Any character (may or may not match line terminators) |
\d
| A digit: [0-9] |
\D
| A non-digit: [^0-9] |
\s
| A whitespace character: [ \t\n\x0B\f\r] |
\S
| A non-whitespace character: [^\s] |
\w
| A word character: [a-zA-Z_0-9] |
\W
| A non-word character: [^\w] |
Boundary matchers | |
^
| The beginning of a line |
$
| The end of a line |
\b
| A word boundary |
\B
| A non-word boundary |
\A
| The beginning of the input |
\G
| The end of the previous match |
\Z
| The end of the input but for the final terminator, if any |
\z
| The end of the input |
Greedy quantifiers | |
X?
| X, once or not at all |
X*
| X, zero or more times |
X+
| X, one or more times |
X{n}
| X, exactly n times |
X{n,}
| X, at least n times |
X{n,m}
| X, at least n but not more than m times |
Reluctant quantifiers | |
X??
| X, once or not at all |
X*?
| X, zero or more times |
X+?
| X, one or more times |
X{n}?
| X, exactly n times |
X{n,}?
| X, at least n times |
X{n,m}?
| X, at least n but not more than m times |
Possessive quantifiers | |
X?+
| X, once or not at all |
X*+
| X, zero or more times |
X++
| X, one or more times |
X{n}+
| X, exactly n times |
X{n,}+
| X, at least n times |
X{n,m}+
| X, at least n but not more than m times |
Logical operators | |
XY
| X followed by Y |
X|Y
| Either X or Y |
(X)
| X, as a capturing group |
Back references | |
\n
| Whatever the nth capturing group matched |
Quotation | |
\
| Nothing, but quotes the following character |
\Q
| Nothing, but quotes all characters until \E |
\E
| Nothing, but ends quoting started by \Q |
Special constructs (non-capturing) | |
(?:X)
| X, as a non-capturing group |
(?imsux-imsux)
| Nothing, but turns match flags on - off |
(?imsux-imsux:X)
|
X, as a non-capturing group with the given flags on - off |
(?=X)
| X, via zero-width positive lookahead |
(?!X)
| X, via zero-width negative lookahead |
(?<=X)
| X, via zero-width positive lookbehind |
(?<!X)
| X, via zero-width negative lookbehind |
(?>X)
| X, as an independent, non-capturing group |
(?#...)
| comment. |
\p
and \P
are supported. It is cooporated
with SRFI-14 charset. However it is kind of tricky. For example regex parser
can reads \p{InAscii}
or \p{IsAscii}
and search charset named
char-set:ascii
from current library. It must have In
or Is
as its prefix.
#/\w+?/i
instead of
like this (regex "\\w+?" CASE-INSENSITIVE)
.
matches
procedure attempts to match the entire input string against
the pattern of regex.
The looking-at
procedure attempts to match the input string against the
pattern of regex.
(define (regex-replace-all pattern text replacement) (regex-replace-all (regex-matcher pattern text) replacement))Text must be string. Replacement must be either string or procedure which takes matcher object and string port as its arguments respectively. Replaces part of text where regex matches with replacement. If replacement is a string, the procedure replace text with given string. Replacement can refer the match result with `
$n
`.
n must be group number of given pattern or matcher.
If replacement is a procedure, then it must accept either one or two
arguments. This is for backward compatibility.
The first argument is always current matcher.
If the procedure only accepts one argument, then it must return a string which
will be used for replacement value.
If the procedure accepts two arguments, then the second one is string output
port. User may write string to the given port and will be the replacement
string.
The regex-replace-first
procedure replaces the first match.
The regex-replace-all
procedure replaces the all matches.
regex
procedure.i
as a
flagx
as a
flagm
as a flags
as a flagu
as a flag.
NOTE: when this flag is set then pre defined charset, such as \d
or
\w
, expand it's content to Unicode characters. Following properties
are applied to charsets.
Ll
and Other_Lowercase
.
Lu
and Other_Uppercase
.
Lt
.
L
, Nl
and
Other_Alphabetic
.
Nd
.
P
.
Sm
, Sc
, Sk
and
So
.
Zs
, Zl
and Zp
.
Cc
, Cf
, Co
, Cn
.
(import (rnrs) (sagittarius socket)) ;; creates echo server socket with port number 5000 (define echo-server-socket (make-server-socket "5000")) ;; addr is client socket (let loop ((addr (socket-accept echo-server-socket))) (call-with-socket addr (lambda (sock) ;; socket-port creates binary input/output port ;; make it transcoded port for convenience. (let ((p (transcoded-port (socket-port sock) ;; on Sagittarius Scheme native-transcoder ;; uses utf8 codec for ASCII compatibility. ;; For socket programming it might be better ;; to specify eol-style with crlf. ;; But this sample just shows how it goes. (native-transcoder)))) (call-with-port p (lambda (p) (put-string p "please type something\n\r") (put-string p "> ") ;; gets line from client. (let lp2 ((r (get-line p))) (unless (eof-object? r) (print "received: " r) ;; just returns message from client. ;; NB: If client type nothing, it'll throw assertion-violation. (put-string p r) (put-string p "\r\n> ") ;; waits for next input. (lp2 (get-line p))))))))) ;; echo server waits next connection. (loop (socket-accept echo-server-socket)))
AF_INET
)
(ai_socktype SOCK_STREAM
)
(ai_flags (+ AI_V4MAPPED
AI_ADDRCONFIG
)) (ai_protocol 0)make-client-socket
uses getaddrinfo(3)
to look it up. The arguments node, service,
ai-family, ai-socktype, ai-flags and ai-protocol are
passed to getaddrinfo(3)
as corresponding parameters. For more detail,
see reference of getaddrinfo(3)
.
Node is a network address, ex) "www.w3.org", "localhost", "192.168.1.1".
Service is a network service, ex) "http", "ssh", "80", "22".
Ai-family is an address family specifier. Predefined specifiers are listed
below.
AF_INET
)
(ai_socktype SOCK_STREAM
)
(ai_protocol 0)make-client-socket
.
call-with-socket
calls a procedure with socket as an argument.
This procedure is analogy with call-with-port
.
shutdown-output-port
and shutdown-input-port
shutdown
output or input connection of a socket associated with port respectively.
make-server-socket
.
Wait for an incoming connection request and returns a fresh connected client
socket.
This procedures is a thin wrapper of POSIX's accept(2)
.
If the calling thread is interrupted by thread-interrupt!
, then
the procedure returns #f.
recv(2)
.
send(2)
.
SHUT_RD
, SHUT_WR
or SHUT_RDWR
.
The socket-shutdown
shutdowns socket.
peer
then it uses socket-peer
. If it is info
,
then it uses socket-info
socket-info-values
.
Converts given IP address object to human readable string.
socket-info-values
.
Converts given IP address object to bytevector.
sendto (2)
.
recvfrom (2)
.
SO_NOSIGPIPE
socket option is set to the created socket.
This procedure is a thin wrapper of socket (2)
.
connect (2)
.
bind (2)
.
listen (2)
.
setsockopt (2)
.
socket-setsockopt!
.
size must be an integer. If the value is positive number, then the
returning value is a bytevector whose element count is size and
contains the socket option converted to byte array. Otherwise it returns
an integer value.
thread-interrupt!
.
This procedure is a thin wrapper of select (2)
.
socket-select
.
timeout is the same as socket-select
.
socket-read-select
can be used to detect if the given sockets have
readable data.
socket-write-select
can be used to detect if the given sockets are
still active.
socket-error-select
can be used to detect if the given sockets are
readable data. This procedure might not be so interesting since it can be
done by socket-read-select
.
family
socktype
flags
protocol
sockaddr
next
get-addrinfo
.&i/o
is raised.
This procedure is a thin wrapper of getaddrinfo (3)
.
sockaddr
slot of given addrinfo.
The returning value can be used socket-recvfrom
and socket-sendto
.
&socket
or &host-not-found
. The first
condition is raised when socket related operation failed, for example
socket-send
. The latter condition is raised when get-addrinfo
is
failed.
NOTE: make-client-socket
and make-server-socket
may raise
&host-not-found
when the given node or service is not a
valid value.
The condition hierarchy is the following:
&i/o + &host-not-found (node service) + &socket (socket) + &socket-connection + &socket-closed + &socket-port (port)
port-ready
procedure is called on socket port and
select (2)
failed.
NOTE: Read or write failure of socket port raises &i/o-read
or
&i/o-write
the same as other ports for compatibility.
NOTE2: This condition may be signalled when get-bytevector-all
is
called on socket port since it checks whether or not the given port is ready.
thread-start!
procedure.
The optional argument name gives the thread a name. The name can be
retrieved calling thread-name
procedure. If the argument is not given,
then the make-thread
procedures creates an unique name.
thread-terminate!
does not return. Otherwise
thread-terminate!
returns an unspecified value; the termination of
the thread will occur before thread-terminate!
returns.
thread-join!
returns
timeout-val if it is supplied, otherwise a "join timeout exception"
is raised. If the thread terminated normally, the content of the
end-result field is returned, otherwise the content of the end-exception
field is raised.thread-resume!
.
EINTR
and cancels blocking system call such
as select (2)
. Currently the only relevant procedure for this is
socket-select
related procedures. See
socket library - Low level APIs.
Currently the procedure uses SIGALRM
on POSIX environment. This
might be changed in future, so do not depend on the signal to interrupt
the call from outside of Sagittarius process.
On Windows, the procedure uses combination of WSAEventSelect
and
WaitForMultipleObjects
. So there is no way to interrupt from
outside of Sagittarius process.
condition-variable-signal!
or
condition-variable-broadcast!
is performed, and no later than the
timeout, if it's given.
&i/o-file-does-not-exist
.
semaphore-close!
and semaphore-destroy!
behaves the
same on Windows.
Europe/Amsterdam
.
If the given name is not found, then GMT
is returned as the fallback.current-time
,
is used.
This procedure considers daylight saving time (DST). Means, if the timezone
has DST, then the return value is depending on the when. For example,
Europe/Amsterdam
has DST so if the when is in DST, then the
returning offset is 7200
, otherwise 3600
.
Europe/Amsterdam
has 2 names, CET
and CEST
. If the
given when is in DST, then CEST
is returned, otherwise CET
is returned.
(let ((tz (timezone "Europe/Dublin")) (now (date->time-utc (make-date 0 0 0 0 24 7 2015 0))) ;; 1:00 - IST 1971 Oct 31 2:00u (no-rule-past (date->time-utc (make-date 0 0 0 0 24 7 1971 0))) ;; 0:00 GB-Eire GMT/IST 1968 Oct 27 (rule-past (date->time-utc (make-date 0 0 0 0 24 7 1968 0)))) (timezone-short-name tz now) ;; => "GMT/IST" (timezone-short-name tz no-rule-past) ;; => "IST" ;; no DST (timezone-offset tz no-rule-past) ;; => 3600 (timezone-raw-offset tz) ;; => 0 (timezone-raw-offset tz no-rule-past) ;; => 3600 (timezone-raw-offset tz rule-past) ;; => 0 (timezone-short-name tz rule-past) ;; => "GMT/IST" )
3600
which is UTC+1 however if it's summer time, then the returning
list doesn't contain some of timezones (e.g. Amsterdam).
The optional argument when specifies the time to consider. If it's not
specified, then the returning value of current-time
is used.
(zone-offset->timezones 3600) ;; => '(#<timezone Etc/GMT-1> ...) ;; offset +15:00 doesn't exist (zone-offset->timezones (* 15 3600)) ;; => '()
zone-offset->timezones*
, the difference is
this procedure creates an anonymous timezone if there's no registered timezone
matching with the given offset.
(zone-offset->timezones* 3600) ;; => '(#<timezone Etc/GMT-1> ...) ;; offset +15:00 doesn't exist (zone-offset->timezones* (* 15 3600)) ;; => '(#<timezone +15:00>)
(debug-print expr)
debug-print
is an internal macro of this library which prints the
read expression and its result.
Following example shows how to enable this;
#!read-macro=sagittarius/debug #!debug (let ((a (+ 1 2))) #?=(expt a 2)) #| #?=(expt a 2) #?- 9 |#
#!debug
enables the debug print.
syntax-rules
. It doesn't consider
locally bound macros.
The returning value may or may not be used as proper Scheme expression.
null-generator
,
all procedures have prefix 'g'
. Arguments named generator
indicates a generator.
(generator->list (giota 5))=> (0 1 2 3 4)
(generator->list (giota 5 10))=> (10 11 12 13 14)
(generator->list (giota 5 10 2))=> (10 12 14 16 18)
unfold
.
(generator->list (gunfold (lambda (s) (> s 5)) (lambda (s) (* s 2)) (lambda (s) (+ s 1)) 0))=> (0 2 4 6 8 10)
reverse-vector->generator
which return end to beginning.
port->char-generator
uses get-char
to read the port. The port->byte-generator
uses get-u8
.
<list>
, <vector>
, <string>
, <bytevector>
and
<port>
.
If the given argument is type of <vector>
, then vector->generator
is used. If the given argument is type of <port>
, then it checks if
it's binary or textual and dispatches apropriate procedure.
(proc v1 v2 ... seed)
, where
v1, v2,...
are the values yielded from the input
generators, and seed is the current seed value. It must return two
values, the yielding value and the next seed.
gtake
is passed, then the value
is filled until the procedure reaches k.
These procedures are analogues of SRFI-1 take
and drop
.
take-while
and drop-while
.
(generator->list (gindex (list->generator '(a b c d e f)) (list->generator '(0 2 4))))=> (a c e)
(generator->list (gselect (list->generator '(a b c d e f)) (list->generator '(#t #f #f #t #t #f))))=> (a d e)
(apply gappend (generator->list generator))The difference is that this procedure can handle infinite generator.
(generator->list (gflatten (list->generator (list '(1 2 3 4) '(a b c d) '(A B C D)))))=> (1 2 3 4 a b c d A B C D)
(generator->list (gflatten (list->generator (list 'ignored '(a b c d) 'ignored '(A B C D)))))=> (a b c d A B C D)
gmerge
procedure is called only one argument, then
it simply returns a generator (if generator1 isn't a generator then
it is coerced).
(generator->list (gmerge < (list->generator '(1 4 5)) (list->generator '(0 2 3))))=> (0 1 2 3 4 5)
proc
.
The proc
is called with the items returned by generator1 and
generator2 if it's given.
The gmap procedure accepts uneven length of generators however one
of the generator must be finite length, otherwise it won't be exhausted.
It is an analogy of map
.
proc
.
This procedure is similar with gmap
. The difference is that the
returning item is filtered if the returning value of proc is #f.
It is an analogy of filter-map
.
(define g (make-coroutine-generator (lambda (yield) (let loop ((i 0)) (when (< i 3) (yield i) (loop (+ i 1))))))) (generator->list g)=> (0 1 2)
glet*
is a macro which is similar to let*
. The difference
is that glet*
check if the bindings are EOF object or not and if it
detects EOF object, then it returns EOF object immediately.
bindings must be one of the following forms:
(var gen-expr)
( gen-expr )
glet*
just check if the value is EOF or not.
(define g (list->generator '(1 2 3))) (list (glet* ((a (g))) a) (glet* ((a (g))) (define b 2) (+ a b)) (glet* ((a (g)) (b (g))) (+ a b)))=> (1 2 #<eof>)
glet*
. This is defined
like the following:
(define-syntax glet1 (syntax-rules () ((_ var expr body body1 ...) (glet* ((var expr)) body body1 ...))))
tar
and zip
.
(import (rnrs) (archive)) ;; extract file "bar.txt" from "foo.zip" (call-with-input-archive-file 'zip "foo.zip" (lambda (zip-in) (do-entry (e zip-in) (when (string=? (archive-entry-name e) "bar.txt") (call-with-output-file "bar.txt" (lambda (out) (extract-entry e out)) :transcoder #f))))) ;; archive "bar.txt" into foo.tar (call-with-output-archive-file 'tar "foo.tar" (lambda (tar-out) (append-entry! tar-out (create-entry tar-out "bar.txt"))))Following sections use type as a supported archive type. More precisely, if it's a supported archive type then there must be a library named
(archive type)
.
(do ((entry (next-entry! archive-input) (next-entry! archive-input))) ((not entry) result) body ...)If the first form is used, then result is #t.
finish!
.
call-with-input-archive
.
call-with-input-archive-port
.
(define-method create-entry ((out <archive-output>) file) (create-entry out file file))So as long as it doesn't have to be distinguished, users don't have to implement this method.
finish!
.
call-with-output-archive
.
call-with-output-archive-port
.
file
or
directory
.
(archive interface)
.
So the library code should look like this;
(library (archive foo) (export) ;; no export procedure is needed (import (rnrs) (close user) (archive interface) ;; so on ...) ;; class and method definitions ... )For archiving, the implementation needs to implement following methods and extends following classes;
make-archive-input, next-entry, extract-entry
<archive-input> <archive-entry>For extracting, the implementation needs to implement following methods and extends following classes;
make-archive-output, create-entry, append-entry!, finish!
<archive-output> <archive-entry>NOTE:
<archive-entry>
may be shared between archiving and extracting.
file
or
directory
.
eql
specializer to specify.
finish!
method for archive input has a default
implementation and it does nothing.
Users can specialize the method for own archive input.
(asn.1)
library. The library supports DER and BER
formats. We do not describe DER or BER format here.
&assertion
<der-encodable>
.
<der-encodable>
.
<der-encodable>
.
<der-encodable>
.
(asn.1)
library.
define-simple
, the
reader is simple-read
and the write is simple-write
,
Then the definition of defined macro would be like this;
define-composite
, the
reader is simple-read
and the write is simple-write
,
Then the definition of defined macro would be like this;
define-class
however slots must be a list
of one of the followings.
eqv?
comparable datum. e.g. keyword.
default can be any object.
count must be a non negative exact integer.
The first form is equivalent with the following form;
(name type #f)
.
And the third form is equivalent with the following form;
(name (type count) #f)
.
The first 2 forms defines a datum slot which the datum is read by reader
passing type and written by writer.
The rest forms defines an array data represented by a vector.
If the type is not defined by neither of the definition forms, then
it is users responsibility to define a method which handles the type.
(import (clos user) (binary data)) ;; use the same name of reader and writer (define-simple-datum-define define-simple sample-read sample-write) (define-composite-data-define define-composite sample-read sample-write) (define-simple <simple> () (a b (c 0)) (lambda (in) (values (get-u8 in) (get-u8 in) (get-u8 in))) (lambda (out a b c) (put-u8 out a) (put-u8 out b) (put-u8 out c))) (define-composite <composite> () ((d :byte 1) (e (:byte 4) #vu8(1 2 3 4)) (f <simple>))) ;; :byte reader and writer (define-method sample-read ((o (eql :byte)) in array-size?) (if array-size? (get-bytevector-n in array-size?) (get-u8 in))) (define-method sample-write ((type (eql :byte)) o out array-size?) (if array-size? (put-bytevector out o) (put-u8 out o)))How to use the defined data structure.
;; read as a <composite> object ;; "deeeeabc" in ascii (define bv #vu8(#x64 #x65 #x65 #x65 #x65 #x61 #x62 #x63)) (call-with-port (open-bytevector-input-port bv) (lambda (in) (let ((s (sample-read <composite> in))) (slot-ref s 'd) ;; => #\d (slot-ref s 'f) ;; => <simple> ))) ;; write <composite> object (call-with-bytevector-output-port (lambda (out) (let* ((s (make <simple> :a 10 :b 20)) (c (make <composite> :f s))) ;; this can be written like this as well (sample-write o out) (sample-write <composite> c out)))) ;; => #vu8(1 1 2 3 4 10 20 0)
get-line
for binary port).
This library exports those convenient procedures
#vu8(#x0d #x0a)
. Default value is
#vu8(#x0a)
If keyword argument transcoder is given, then returning value will be
converted to string.
(sagittarius)
for convenience. See
Sagittarius extensions.
endianness
macro.
Write v to out as unsigned/signed 16/32/64 bit integer or
32/64 bit floating number.
(sagittarius)
for convenience. See
Sagittarius extensions.
endianness
macro.
Read a number from in as unsigned/signed 16/32/64 bit integer or
32/64 bit floating number.
+default-chunk-size+
is used.
(weinholt struct pack)
library.
(pack "!c" 128)=> #vu8(128)
(pack "s" 100)=> #vu8(100 0)
(pack "!s" 100)=> #vu8(0 100)
(pack "!d" 3.14)=> #vu8(64 9 30 184 81 235 133 31)
(pack "!xd" 3.14)=> #vu8(0 0 0 0 0 0 0 0 64 9 30 184 81 235 133 31)
(pack "!uxd" 3.14)=> #vu8(0 64 9 30 184 81 235 133 31)
#\*
means
indefinite length repetition.
(pack "3c" 1 2 3)=> #vu8(1 2 3)
(pack "*c" 1 2 3 4)=> #vu8(1 2 3 4)
(pack "3c" 1 2 3 4)=> &syntax
(pack (car '("3c")) 1 2 3 4)=> &error
pack!
.
If the second form is used, then unpacking is done from the given offset.
(unpack "!SS" #vu8(0 1 0 2))=> 1 2
(unpack "!SS" #vu8(0 1 0 2 0 3) 1)=> 2 3
(unpack "!uSS" #vu8(0 1 0 2 0 3) 1)=> 256 512
#\*
, otherwise #f is returned.
(format-size "!xd")=> 16
(format-size "!uxd")=> 9
(format-size "*c")=> #f
(format-size "*c" 1 2 3 4)=> 4
pack
and unpack
are syntactic keywords.
Defines packing extension to given char. This macro can not overwrite
the predefined characters. ** can be followings;
s8
, u8
, s16
, u16
, s32
, u32
,
s64
, u64
, f32
, and f64
.
;; defining char to u8 converter (define-u8-packer (#\A v) (pack (char->integer v)) (unpack (integer->char v))) (pack "AA" #\a #\b) ;; => #vu8(97 98) (unpack "AA" #vu8(97 98)) ;; => #\a #\b
buffer
and size
fields.
buffer
field of given buffer.
The type of buffer
field is implementation specific.
size
field of given buffer.
The returning value shall represents how much buffer of the given buffer
is consumed.
size
field of given buffer
.data
field which contains overflowing data.
&pre-allocated-buffer-overflow
condition, otherwise #f.
data
field value of condition.
The condition must be a &pre-allocated-buffer-overflow
condition.
<pre-allocated-buffer>
.
bytevector-u8-set!
bytevector-u16-set!
bytevector-u32-set!
bytevector-u64-set!
bytevector-s8-set!
bytevector-s16-set!
bytevector-s32-set!
bytevector-s64-set!
bytevector-ieee-single-set!
bytevector-ieee-double-set!
The endianness is passed to the above procedures if required.
This procedure also updates the size
field of binary-buffer.
(- (bytevector-length bv) start)
.
This procedure also updates the size
field of binary-buffer.
bytevector-u8-set!
bytevector-s8-set!
bytevector-u16-set!
bytevector-u32-set!
bytevector-u64-set!
bytevector-s16-set!
bytevector-s32-set!
bytevector-s64-set!
bytevector-ieee-single-set!
bytevector-ieee-double-set!
The endianness is passed to the above procedures if required.
This procedure updates the size
field of binary-buffer if
sum of given index and number of bytes set in the buffer exceeds
the size of the buffer.
(- (bytevector-length bv) start)
.
This procedure updates the size
field of binary-buffer if
sum of given index and number of bytes set in the buffer exceeds
the size of the buffer.
&pre-allocated-buffer-overflow
,
when it tries to exceed the pre-allocated buffer.
size
field value of buffer
field.
&pre-allocated-buffer-overflow
.
bytevector->integer
.
All procedures take bytevector as its arguments.
!
freshly allocate a new bytevector as it's return
value. If the given bytevectors are not the same sized, then the smallest
size will be allocated.
The procedures with !
takes first argument as the storage of the result
and return it.
(bytevector-slices #vu8(1 2 3 4 5 6) 3)=> (#vu8(1 2 3) #vu8(4 5 6))
(bytevector-slices #vu8(1 2 3 4) 3)=> (#vu8(1 2 3) #vu8(4))
;; the given bytevector bv is #vu8(4) (bytevector-slices #vu8(1 2 3 4) 3 :padding (lambda (bv) #vu8(4 5 6)))=> (#vu8(1 2 3) #vu8(4 5 6))
;; this is valid as well so that bytevector-slices doesn't check the ;; return value (bytevector-slices #vu8(1 2 3 4) 3 :padding (lambda (bv) #f))=> (#vu8(1 2 3) #f)
(bytevector-split-at* #vu8(1 2 3 4 5) 3)=> #vu8(1 2 3) and #vu8(4 5)
(bytevector-split-at* #vu8(1 2) 3 :padding (lambda (bv) #vu8(1 2 3)))=> #vu8(1 2 3) and #vu8()
(bytevector-split-at* #vu8(1 2) 3 :padding (lambda (bv) #f))=> #f and #vu8()
0
. The comparison procedures are <
, >
, <=
and >=
, respectively.
(list->string (map integer->char (bytevector->u8-list bv)))This procedure is implemented in a memory efficient way.
bytevector-reverse!
reverses destructively.
0 <= n <= 255
.
This is useful to handle bytevectors as if they are ASCII strings.
0 <= o <= 255
, otherwise #f.u8?
. Otherwise #f.
u8-set?
. u8 should satisfy
u8
. The procedure doesn't check if arguments satify this.
Returns #t if given u8-set contains u8.
u8-set?
.
It is users' responsibility to pass ASCII string.
u8-set?
by dropping outside of ASCII characters.
bytevector-take
takes from left and the bytevector-take-right
takes from right.
bytevector-drop
drops from left and the bytevector-drop-right
drops from right.
" \r\f\v\n\t"
.
The optional arguments start and end specify from and until where
the procedure trims. The default value is 0 for start and the length
of given bytevector for end.
bytevector-pad
pads left side of given bv. The
bytevector-pad-right
pads right side of given bv.
The optional arguments start and end specify from and until where
the procedure pads. The default value is 0 for start and the length
of given bytevector for end.
(bytevector-append (bytevector-copy s1 0 start1) (bytevector-copy s2 start2 end2) (bytevector-copy s1 end1 (string-length s1)))
(util concurrent)
. This library provides
future related APIs.(import (rnrs) (util concurrent)) ;; creates 5 futures (define futures (map (lambda (i) (future (* i i))) '(1 2 3 4 5))) ;; wait and retrieve the results (map future-get futures)=> (1 4 9 16 25)
(future (class <simple-future>) expr ...)
<simple-future>
provides by
this library won't disturb the execution. Thus calling this procedure
doesn't do anything but changing the future's state.
NOTE: once this procedure is called, then calling future-get
with future raises a &future-terminated
.
(import (rnrs) (util concurrent)) (define f (future (display "cancelled") (newline))) (future-cancel f) (future-get f)=> &future-terminated
"cancelled"
.
future-cancel
, otherwise #f.done
and terminated
.
done
is set when future-get
is called.
terminated
is set when future-cancel
is called.
&future-terminated
.
&future-terminated
condition.
Retrieve terminated future from condition.
<future>
implementation of this library.(util concurrent)
. This library provides
executor related APIs.java.util.concurrent
package. The library provides 2 types
of executors, thread pool executor and fork join executor. The first
one uses thread pool, described below section, and the latter one
just creates a thread per task. The following is an example how to use
the executors:
(import (rnrs) (util concurrent)) ;; creates executor which uses 5 threads and push all tasks (define executor (make-thread-pool-executor 5 push-future-handler)) ;; creates 10 futures (define futures (map (lambda (i) (future (class <executor-future>) (* i i))) '(1 2 3 4 5 6 7 8 9 10))) ;; execute futures (for-each (lambda (future) (execute-future! executor future)) futures) ;; wait/retrieve the results (map future-get futures)=> (1 4 9 16 25 36 49 64 81 100)
push-future-handler
waits until the
previous taskes are finished.
state
.
state
field of the executor.(define (executor-submit! e thunk) (let ((f (make-executor-future thunk))) (execute-future! e f) f))
(util concurrent thread-pool)
as its
underlying thread managing. So once the threads are created then the
thread holds its environment until the executor is shutdown. In other
words, if a task changes the dynamic environment, then the next task
uses the changed dynamic environment. The following example describes
how dynamic environments works on this executor:
(import (rnrs) (util concurrent) (srfi :39)) (define *one* (make-parameter 1)) (define executor (make-thread-pool-executor 1)) (let ((f1 (make-executor-future (lambda () (*one* 2) 1))) (f2 (make-executor-future (lambda () (*one*))))) (execute-future! executor f1) (future-get f1) (execute-future! executor f2) (future-get f2))=> 2
*one*
is initialised with
the initial value 1
during thread creation.
<executor>
.abort-rejected-handler
is used.
push-future-handler
is specified during the executor creation.
push-future-handler
is specified.
&rejected-execution-error
.
This is the default handler.
abort-rejected-handler
is called.
&rejected-execution-error
object.
Otherwise #f.&rejected-execution-error
object.
Retrieves the rejected future and executor, respectively.
<simple-future>
.
<executor>
.shutdown
.<executor-future>
. This type inherits
<future>
.
(util concurrent)
. This library provides
thread pool APIs.(import (rnrs) (util concurrent)) ;; pooling 5 thread (define thread-pool (make-thread-pool 5)) (for-each (lambda (i) (thread-pool-push-task! thread-pool (lambda () (* i i)))) '(1 2 3 4 5 6 7 8 9 10)) ;; waits until all tasks are done (thread-pool-wait-all! thread-pool) ;; release thread-pool (thread-pool-release! thread-pool)
thread-pool-thread
procedure.
terminate
, then the procedure
terminates the thread instead of joining.
NOTE: terminating a thread is very dangerous operation, so don't use casually.
(thread-pool-current-thread-id)
procedure to retrieve thread id from
managed threads.
It signals an error if the given thread is not a managed thread.
NOTE: if the thread is terminated, then the procedure also signals an error.
(util concurrent)
. This library provides
shared queue APIs.(import (rnrs) (util concurrent) (srfi :18)) (define shared-queue (make-shared-queue)) (define thread (thread-start! (make-thread (lambda () ;; waits until the queue has an element (let ((value (shared-queue-get! shared-queue))) (* value value)))))) (shared-queue-put! share-queue 5) (thread-join! thread)=> 25
max-length
and overflows, then it wait until
it's available.
If the optional argument timeout is specified, then the procedure
only waits specified amount of time. timeout can be either integer
or time object defined in SRFI-19. If the queue didn't get any object within
the timeout, then timeout-val is returned.
equal?
.
(util concurrent)
. This library provides
actor model like APIs.(import (rnrs) (util concurrent actor) (match)) (define (open-account initial-amount) (define balance initial-amount) (make-shared-queue-channel-actor (lambda (input-receiver output-sender) (let loop () (match (input-receiver) (('withdrow how-much) (if (< balance how-much) (output-sender "invalid amount") (begin (set! balance (- balance how-much)) (output-sender (cons how-much balance)))) (loop)) (('deposite a) (if (negative? a) (output-sender "invalid amount") (begin (set! balance (+ balance a)) (output-sender (cons 0 balance)))) (loop)) (('close) #t) (else "invalid message")))))) (define client (open-account 1000)) (actor-send-message! client '(withdrow 100)) (actor-send-message! client '(deposite 100)) (actor-send-message! client '(close)) (actor-receive-message! client) ;; => (100 . 900) (actor-receive-message! client) ;; => (0 . 1000)
make-shared-priority-queue-channel-actor
is used, then the
compare must be a procedure which takes 2 arguments and returns the
comparison result of given 2 arguments. The value should be, -1, 0 or 1.
task must be an procedure accepts 2 argument, input-receiver and
output-sender. The procedures' signatures are the followings:
The input-receiver receives a message from outside of the actor.
The output-sender sends a message message to outside of the actor.
Messages can be sent to an actor via actor-send-message!
, and be
received from an actor via actor-receive-message!
.
The optional arguments timeout and timeout-val are given, it shall
behave the same as shared-queue-get!
or shared-queue-put!
.
shared-queue-put!
.
shared-queue-get!
.
thread-join!
.
libtomcrypt
's functionalities. The library is public
domain. Thank you for the great library.
Note: the libtomcrypt
is a huge cryptographic library and I am not so
good with cryptographics, so the (crypto)
library is not totally tested.
Just the functionalities which I usually use are tested. If you find a bug or
wrong documentation, pleas report it.
(crypto)
library supports both symmetric cryptography and public/private
key mechanism. For public/private key, it only supports RSA for now.
crypto-object
.
crypto-object
can be either cipher
or key
.
(crypto)
library exports the algorithm below.
The symmetric key algorithms.
cipher
procedure.
test must be fixnum.
If test is too small for the cipher, it will raise an error.
Note: this procedure is for helper. It is designed to use check keysize you want
to use.
encrypt
encrypts given plain text pt according to the given
cipher.
cipher-encrypt
. The difference is that this
procedure returns 2 values, encrypted pt and calculated tag if the
given cipher supports authentication.
If the keyword argument tag-size is specified and must be an integer,
then the returning tag has the specified size. If the cipher supports
less size than the specified size, then the remaining tag contains unspecified
value. To retrieve the maximum length of tag, use cipher-max-tag-size
.
decrypt
decrypts given encrypted text ct according to the given
cipher.
cipher-decrypt
. The difference is that this
procedure returns 2 values, decrypted ct and calculated tag if the
given cipher supports authentication.
If the keyword argument tag-size is specified and must be an integer,
then the returning tag has the specified size. If the cipher supports
less size than the specified size, then the remaining tag contains unspecified
value. To retrieve the maximum length of tag, use cipher-max-tag-size
.
cipher-decrypt
. The difference is that this
procedure validates the calculated tag. If the given tag and
calculated tag are not the same, then &decrypt
is raised.
NOTE: if the tag is *not* calculated by the cipher, then this procedure
always raises an error.
0
.
cipher-encrypt
or
cipher-decrypt
. Otherwise the filled value is unspecified.
cipher-encrypt
or
cipher-decrypt
. Otherwise the filled value is unspecified.
pkcs1-emsa-pss-encode
. And the rest keyword arguments will be passed to
encoder. Supported encoders are described below.
pkcs1-emsa-pss-verify
. And the rest keyword arguments will be passed to
verifier. Supported verifiers are described below.
iv-parameter
is a parameter contains an IV.
MODE_CBC
.
<iv-parameter>
.
MODE_CTR
.
iv is passed to parent constructor.
The followings are description of keyword parameters.
rounds specify how many times the cipher rounds the key.
ctr-mode specifies counter mode. The possible mode is blow.
<ctr-parameter>
.
pkcs5-padder
.
RSA
.
Generates a key pair object.
Default implementation supports RSA key geneartion and options can be
keyword arguments described below.
size keyword argument is decides key length. Default value is 1024.
prng keyword argument is given, it will be passed to random-prime
.
For more detail, see (math random) library. Default
value is (secure-random RC4)
.
e keyword argument is an exponent. Usually it does not have to be
specified with other number. Default value is 65537.
RSA
.
Returns private key object.
Default RSA implementation options can be these arguments.
RSA
.
Returns public key object.
Default RSA implementation opt can be these arguments.
bytevector-xor
and bytevector-xor!
respectively.
For more detail, see (util bytevector).
(hash-algorithm SHA-1)
) (mgf mgf-1) (salt-length #f)
(prng (secure-random RC4)
)(hash-algorithm SHA-1)
) (mgf mgf-1)
(prng (secure-random RC4)
)pkcs1-emsa-pss-encode
.
pkcs1-emsa-pss-encode
.
pkcs1-emsa-pss-encode
.
#vu8(#xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6)
specified by the specification.
#vu8(#xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6)
specified by the specification.
&error
.
Base condition type of all cryptographic conditions.assertion-violation
.
mechanism should be a name of cryptographic algorithm.
Raises &encrypt-error
.
assertion-violation
.
mechanism should be a name of cryptographic algorithm.
Raises &decrypt-error
.
assertion-violation
.
Raises &encode-error
.
assertion-violation
.
Raises &decode-error
.
&crypto-error
This condition will be raised when key unwrap failed due to the
integrity check error.
(import (rnrs) (crypto) (clos user) (sagittarius)) (define (sample-encrypt pt key) pt) (define (sample-decrypt ct key) ct) (define-class <sample-cipher-spi> (<cipher-spi>) ()) (define-method initialize ((o <sample-cipher-spi>) initargs) (slot-set! o 'name 'sample) (slot-set! o 'key #f) (slot-set! o 'encrypt sample-encrypt) (slot-set! o 'decrypt sample-decrypt) (slot-set! o 'padder #f) (slot-set! o 'signer (lambda _ #vu8())) (slot-set! o 'verifier (lambda _ #t)) (slot-set! o 'keysize (lambda _ 0))) (define sample :sample) (register-spi sample <sample-cipher-spi>) ;; test sample-cipher (define sample-cipher (cipher sample #f)) (define message (string->utf8 "sample message")) (let ((encrypted-message (encrypt sample-cipher message))) (decrypt sample-cipher encrypted-message)) ;; -> #vu8(115 97 109 112 108 101 32 109 101 115 115 97 103 101)The sample code actually does nothing. If you want to see real working code,
ext/crypto/crypto/key/rsa.scm
might be a good example for you.
The basic idea of creating a new cipher is that you need to define own subclass
of <cipher-spi>
and register it.
pkcs5-padder
which takes 3
arguments, bytevector, block-size and padding flag. This is because the
procedure can be used by multi ciphers. And custom cipher must know its own
block size.
These slots are optional.
encrypt
, decrypt
,
sign
and verify
to be used.cipher-update-aad!
is called.
cipher-tag!
is called.
initialize
method) takes at least 3 arguments, key,
:mode-parameter
keyword and parameter passed to
make-cipher
. The rest of other arguments are also passed if exist.
equal?
spi must be subclass of <cipher-spi>
NOTE: We recommend to make mark the same as example code does and export
the registered mark. And the mark must be unique enough not to
overwrite existing SPI names.
e.g. :rsa
, :dsa
and :ecdsa
are already used for
RSA, DSA and ECDSA
cipher
procedure actually creates an instance of SPI class and set it to
the cipher object. So users need not to know about the implementation and if the
implementation supply default parameter then users even can use it by default.
This is the class hierarchy of these crypto objects.
+ <top> + <crypto> + <cipher> + <cipher-spi> + <builtin-cipher-spi> <- default implementations of symmetric keys. + <rsa-cipher-spi> <- default RSA implementation + <key> + <symmetric-key> + <builtin-symmetric-key> <- default symmetric key. ex. DES + <asymmetric-key> + <private-key> + <rsa-private-key> + <rsa-private-crt-key> + <public-key> + <rsa-public-key>The
<cipher>
and builtin-
prefixed classes can not have any
subclass.
cipher
- Use make-cipher
instead.encrypt
- Use cipher-encrypt
instead.decrypt
- Use cipher-decrypt
instead.sign
- Use cipher-signature
instead.verity
- Use cipher-verify
instead.register-spi
- Use register-cipher-spi
instead.(dbd odbc)
DBD library.
(import (dbi)) (define conn (dbi-connect "dbi:odbc:server=XE" :username "username" :password "password")) (let* ((query (dbi-prepare conn "SELECT * FROM table WHERE id > ?")) (result (dbi-execute-query! query 1))) (do ((row (dbi-fetch! result) (dbi-fetch! result))) ((not row)) (vector-for-each (lambda (col) (print col)) row)))There is nothing specific to the underlying database system except the argument
"dbi:odbc:server=XE"
passed to dbi-connect
, from which
dbi
library figures out that it is an access to odbc
, loads
(dbd odbc)
library and let it handle the specific operations.
If you want to use other database named boo, then you just need to pass
"dbi:boo:parameter"
to dbi-connect
instead. As long
as you have (dbd boo)
installed then everything stays the same.
dbi:driver:options
driver part names a specific driver. You need to have a corresponding
driver library, (dbd driver)
, installed in your system.
Interpretation of the options part is up to the driver. Usually it is
in the form of key1=value1;key2=value2;...
. However the DBD
implementations can have different format so you need to check the document
of each driver for exact specification of options.
rest argument will be passed to the underlying procedure.
NOTE: username, password and auto-commit are strongly
encouraged to be implemented in the DBD library.
If a connection to the database is successfully established, a connection
object is returned.
?
.
(dbi-prepare conn "insert into tab (col1, col2) values (?, ?)")
(dbi-prepare conn "select * from tab where col1 = ?")If args is not null, then the procedure shall bind given parameters to the place holder.
dbi-execute!
shall return a integer value representing affected
row count.
The dbi-execute-query!
shall return a result set object which can be
used with dbi-fetch!
or dbi-fetch-all!
. The implementation may
allow to return a specific result set object and it is users' responsibility
to use it with fetching the result.
NOTE: There is a default implementation of dbi-execute-query!
and
returns the given query as a result set object.
dbi-fetch!
shall return a vector representing the query result, if
there is no more data available it shall return #f.
The dbi-fetch-all!
shall return a list of vectors representing the
query result.
NOTE: There is a default implementation of dbi-fetch-all!
, it calls
dbi-fetch!
until it returns #f.
&dbi-error
is a sub condition
of &error
.
All DBI related condition should inherit this condition.
condition-driver-name
returns missing driver name.
(dbd foo)
where foo is the name of the driver.
The library have to implement a creating a driver procedure and several
classes and methods as explained below.
The method described above section must behave as it expected there, especially
behaviours described with shall.
make-foo-driver
.
And it is strongly encouraged to be implemented as a subclass of
<dbi-driver>
for future extension.
<dbi-connection>
. An instance of this class is created
by dbi-make-connection
. It needs to keep the information about the
actual connections.<dbi-driver>
for actual driver instance.<dbi-query>
to keep driver specific information
of prepared statement.dbi-connect
, and responsible to connect
to the database and to create a connection object. It must return a connection
object or raise an error which should be a sub condition of &dbi-error
.
options is the option part of the data source name (DSN) given to
dbi-connect
. options-alist is an assoc list of the result of
parsing options. Both are provided so that the driver may interpret
options string in nontrivial way.
For example, given "dbi:foo:myaddressbook;host=dbhost;port=8998"
as DSN, foo's dbi-make-connection
will receive
"myaddressbook;host=dbhost;port=8998"
as options, and
(("myaddressbook" . #t) ("host" . "dbhost") ("port" . "8998"))
as
options-alist.
After options-alist, whatever given to dbi-connect
are passed.
The driver is strongly encouraged to implement :username
,
:password
and :auto-commit
(if the database is supported)
keyword arguments to specify the authentication information and commit mode.
<dbi-query>
or its subclass.
sql is an SQL statement. It may contain placeholders represented by
'?'
. The implementation must accept it to keep DBI portable even though
the database doesn't.
dbi-close
to be
called on a connection or a query which has already been closed.
(import (dbm)) ;; Open the database (define *db* (dbm-open (dbm-type->class 'dumb) :path "dumb.db")) ;; Put the value to the database (dbm-put! *db* "key1" "value1") ;; Get the value from the database (dbm-get *db* "key1") ;; Iterate over the database (dbm-for-each *db* (lambda (key val) #| do something useful |#)) ;; Close the database (dbm-close *db*)
dbm-open
.
dbm-open
creates one.
dbm-open
truncates it.
write/ss
, to store in the database and convert back Scheme
values, using read/ss
, to retrieve from the database.
<dbm>
and its subclasses.<dbm>
.
(dbm dbmtype)
. For
example, to get the foo DBM then the library name must be
(dbm foo)
.
procedure key value r
, where r is knil for the
first call of procedure, and the return value of the previous call for
subsequent calls. Returns the result of the last call of procedure.
If no data is in the database, knil is returned.
dbm-map
.
<deque>
.+inf.0
.deque-push!
call. Besides, if the value of the result of
mtdeque-max-length
is positive, and adding objs makes the
number of element in deque exceeds it, an error is raised and
deque won't be modified. (If the maximum length is zero, this procedure
always fail. Use deque-push/wait!
below.)
deque-push!
, when deque is an mtdeque, all objects are added
atomically, and the value of max length is checked. See deque-push!
above
for more detail.
The name unshift is taken from Perl.
deque-push!
and deque-unshift!
, respectively, except
that these don't modify deque if it already contains objs (elements
are compared by two-argument procedure eq-proc).
When deque is an mtdeque, all objects are added atomically, and the max
length is checked. See deque-push!
above for the detail.
deque-pop/wait!
or deque-shift/wait!
to use
such a deque as a synchronisation device.
The name shift is take from Perl.
deque-pop-all!
is constructed from the end
of queue and deque-shift-all!
's one is constructed from the front
of queue.
See also deque->list
below.
<deque>
by giving the class to the
optional class arguments. The optional initargs arguments are
passed to the constructor of class.
deque-shift-all!
, the content of deque remains intact.
The returning list is a copy of the content. So modifying the list won't
affect deque.
deque-unshift/wait!
and deque-push/wait!
), or the mtdeque is empty
(for deque-shift/wait!
and deque-pop/wait!
). The blocked caller
thread is unblocked either the blocking condition is resolved, or the
timeout condition is met.
The optional timeout argument specifies the timeout condition. If it
is #f, those procedure wait indefinitely. If it is a real number, they wait
at least the given number of seconds.
In case the call is blocked then timed out, the value of timeout-val is
returned, which default value is #t.
When deque-unshift/wait!
and deque-push/wait!
succeeds without
hitting timeout, they return #t.
(sagittarius)
library.
(native-transcoder)
returns.
file->list
. The procedures defined as following;
(file->list read/ss
path)
(file->list get-line
path)
respectively.
.
. If this is #f,
the procedure excludes hidden files.directory
or file
. No symbolic likes are given.directory
, symbolic-link
or file
.
Apply given proc to the found paths starting from path and returns
unspecified value. The second argument of proc indicates the file type
with following meaning;
directory
symbolic-link
file
find-files
.
directory
, symbolic-link
or file
.
Process the path string starting from path with given proc and
returns a list which elements are the result value of proc.
The keyword arguments are the same as path-for-each
.
(sagittarius)
for convenience. See
Sagittarius extensions.
(sagittarius)
for convenience. See
Sagittarius extensions.
mkdir -p
and rm -rf
,
respectively.
path-for-each
.
args-fold
provided by SRFI-37. It takes a list
of arguments, args, and scans it to find Unix-style command-line
options and binds their values to local variables according to bind-spec,
then executes body.
Following is the example how to use;
(define (usage args) ...) (define (main args) (with-args args ((verbose (#\v "verbose") #f #f) (file (#\f "file") #t (usage args)) (debug-level (#\d "debug-level") #t "0") . rest) ...))The bind-spec must be one of the following forms;
*
default)
*
is syntactic keyword and the
passed value will be packed to list. Thus the script can take more than one
the same options.
If rest is not presented and args contains non listed argument,
then it raises an &assertion
. If it is, then it will pack the rest of
non listed argument as a list.
hashtable-for-each
returns unspecified value. The
hashtable-map
returns a list of the proc result.
These procedures are analogous to for-each
and map
respectively.
fold
.
make-eq-hashtable
. If it's specified then it
will use make-hashtable
to create a hashtable.
heap-entry-key
and heap-entry-value
procedures, respectively.
heap-compare
, otherwise it's an error.
If entry/key is an entry then this operation is done in amortized
O(log n). If not, then O(n).
NOTE: If entry/key is an entry, then it must exist in heap.
However the procedure won't check so it is user's responsibility to
make sure.
merge-heaps
or merge-heaps!
instead.
for-each
and map
, expect proc receives the index
as the first argument.
(map-with-index list '(a b c) '(e f g))=> ((0 a e) (1 b f) (2 c g))
(intersperse '+ '(1 2 3))=> (1 + 2 + 3)
(intersperse '+ '(1))=> (1)
(intersperse '+ '())=> ()
take*
; this is, it is shorter than
k by default, or added padding if fill? is true.
(slices '(a b c d e f g) 3)=> ((a b c) (d e f) (g))
(slices '(a b c d e f g) 3 #t 'z)=> ((a b c) (d e f) (g z z))
split-at
defined in SRFI-1 library. Returns the results of
take*
and drop*
.
(split-at* '(a b c d) 6 #t 'z)=> (a b c d z z) and ()
take
and drop
defined in SRFI-1
library. These won't raise an error when k is larger than the size of the
given list.
If the list is shorter than k elements, take*
returns a copy of
list by default. If fill? is true, padding is added to the
result to make its length k.
On the other hand, drop*
just returns as empty list when the input list
is shorter than k elements.
(take* '(a b c d) 3)=> (a b c)
(take* '(a b c d) 6)=> (a b c d)
(take* '(a b c d) 6 #t)=> (a b c d #f #f)
(take* '(a b c d) 6 #t 'z)=> (a b c d z z)
(drop* '(a b c d) 3)=> (d)
(drop* '(a b c d) 5)=> ()
(test expr ...)
, except that the result of the last
expr must be a list, and it is spliced into the resulting list,
like unquote-splicing.
(test => proc)
, except that the result of the last
proc must be a list, and it is spliced into the resulting list,
like unquote-splicing.
(let ((alist '((x 3) (y -1) (z 6)))) (cond-list ((assoc 'x alist) 'have-x) ((assoc 'w alist) 'have-w) ((assoc 'z alist) => cadr)))=> (have-x 6)
(let ((x 2) (y #f) (z 5)) (cond-list (x `(:x ,x)) (y `(:y ,y)) (z `(:z ,z))))=> (:x 2 :z 5)
(util logger)
provides logger and appender style logging utilility.
Loggers determine loging level and appenders determin how to write logs.
This example shows the concept.
(import (rnrs) (util logging)) ;; Appenders (define console-appender (make-appender "[~w5] ~l ~m")) (define file-appender (make-file-appender "[~w5] ~l ~m" "useful.log")) ;; Logger (define logger (make-logger +debug-level+ console-appender file-appender)) ;; This won't be logged since the logger level is debug. (trace-log logger "trace log message") (debug-log logger "debug log message") ;; If the logging requires heavy process, then it's better to ;; check the level (when (logger-info? logger) (let ((message (construct-message))) (info-log logger message))) ;; stop logging (terminate-logger! logger)
<logger>
is a base type of loggers.
logger?
returns #t if obj is a logger otherwise #f.
make-logger
creates a logger whose threshold is threshold and
appenders are appenders. The threshold must be one of the
followings:
+trace-level+
is the lowest level (0
) and
+fatal-level+
is the highest level (5
). The values are integers
so users can extend the level for both side.
<async-logger>
is a type of asynchronous loggers. It inherits
the <logger>
.
async-logger?
returns #t if obj is an asynchronous logger
otherwise #f.
make-async-logger
creates an asynchronous logger. The arguments are
passed to parent protocol.
Asynchronous logger logs message asynchronously. Means it creates a background
thread and lets it log. It is useful if a logger has a lot of appenders and
logging process may take a lot of time.
To stop background thread, terminate-logger!
needs to be called. It
is users responsibility to do it.
level-log
procedures log message on logger if
logger has its threshold lower than the level.
logger-level?
procedures check if the logger has
threshold lower than level.
appender-finish
for all appenders of give logger.
If the logger is an asynchronous logger, then it also stops background
thread.
current-output-port
.
appender?
returns #f if obj is an appender otherwise #f.
make-appender
creates an appender. The log-format argument
must be a string and specifying the format of the log line.
The log-format can contains place holders stating with the character
#\~
. The followings are the defined place holders:
#\wdate-format
#\{ #\}
. The format is passed to the date->string
procedure defined in SRFI-19.
#\l
#\m
#\a[n]
#\a
"[~w5] ~l ~m"
and logging with info level.
(define logger (make-logger +info-level+ (make-appender "[~w5] ~l ~m"))) (info-log logger "message of the log") ;; [2016-09-06T12:32:06] info message of the log
<appender>
. This appender
emits log messages to the file named filename.
file-appender?
returns #f if obj is a file appender otherwise #f.
make-file-appender
creates a file appender. The log-format is
passed to parent protocol. The file creation is done with file options of
no-fail
, no-truncate
and append
. Thus if the file exists
then it would append the log line.
The given filename will be converted to absolute path so changing
directory will not affect the log file location.
<file-appender>
.
This appender emits log message to the file named filename and if
the file size is more than rolling-size, then it renames the old file
to indexed file and new log file named filename is created.
rolling-file-appender?
returns #f if obj is a rolling file
appender otherwise #f.
<file-appender>
.
This appender emits log message to the file named filename and if
the date string of last file modified time formatted to date-pattern
is differ from log time, then the appender rolls the old log file to
a backup file. The backup file is concatenation of filename and
last modified date.
daily-rolling-file-appender?
returns #f if obj is a daily rolling
file appender otherwise #f.
(import (rnrs) (rfc smtp) (rfc smtp authentications) (util logging) (clos user)) (define-record-type (<smtp-appender> make-smtp-appender smtp-appender?) (parent <appender>) (fields (immutable connection smtp-appender-connection) (immutable username smtp-appender-username) (immutable password smtp-appender-password)) (protocol (lambda (p) (lambda (format host port username password) ((p format) (make-smtp-connection host port) username password))))) (define-method append-log ((appender <smtp-appender>) log) (let ((message (format-log appender log)) (conn (smtp-appender-connection appender))) (guard (e (else (report-error e))) (smtp-connect! conn) (when (smtp-authentication-required? conn) (let* ((methods (smtp-connection-authentication-methods conn)) (username (smtp-appender-username appender)) (password (smtp-appender-password appender)) (method (cond ((memq 'PLAIN methods) (list (smtp-plain-authentication username password))) ((memq 'PASSWORD methods) (let-values ((init&next (smtp-login-authentication username password))) init&next)) (else #f)))) (if methods (apply smtp-authenticate! conn method) (begin (smtp-disconnect! conn) (error 'append-log "not supported"))))) (smtp-send! conn (smtp:mail (smtp:from "Takashi Kato" "ktakashi@ymail.com") (smtp:to "Takashi Kato" "ktakashi@ymail.com") (smtp:subject "Logging with email") message)) (smtp-disconnect! conn))))The example is not really useful since it sends only the fixed recipient with fixed format. If you need to use it, you need to modify. Only what users need to do to create an appender is the followings:
<appender>
.append-log
method with the above record.<log>
or its subtype. This method should
emit logs.
terminate-logger
is called.
Implementation should release resource of the appender.
<log>
or its subtype.
The method must return a string representation of given log.
The default implementation handles the log format described in the
make-logger
description.
<log>
has 4 fields when
, level
, message
and
arguments
. By the default creation, they are UTC time object, symbol
of log level, log message and a vector of extra logging arguments, respectively.
clause*
must the following form:
(loggers (logger-name make-logger) ...)
loggers
is an auxiliary syntax. If the loggers
clause is specified, then the macro stores the logger logger-name which
is created by make-logger thunk as its predefined loggers.
(crypto)
library.
This library also uses libtomcrypt
as its implemention except prime
number operations.
(math random)
, (math hash)
, (math prime)
and
(math helper)
System
prng uses platform random generator. For example, on
Unix like environment, this uses /dev/urandom
or /dev/random
if
the first option is not available.
(do ((i 0 (+ i 1)) (r '() (cons (random (pseudo-random RC4) 10) r))) ((= i 10) r))=> '(0 0 0 0 0 0 0 0 0 0)
(let ((rc (pseudo-random RC4))) (do ((i 0 (+ i 1)) (r '() (cons (random rc 10) r))) ((= i 10) r)))=> '(3 4 0 6 7 4 3 4 2 0)
secure-random
below.
read-random-bytes
.
;; the code snipet is from math/mt-random (define-class <mersenne-twister> (<user-prng>) (;; The array for the state vector ;; using bytevector, it needs to be 64 bit aligned. (state :init-keyword :state :init-form (make-bytevector (* NN 8))) ;; mti==NN+1 means MT[NN] is not initialized (mti :init-keyword :mti :init-form (+ NN 1)))) (define-method initialize ((o <mersenne-twister>) initargs) (call-next-method) (let ((seed (get-keyword :seed initargs #f))) (slot-set! o 'set-seed! mt-set-seed) (slot-set! o 'read-random! mt-read-random!) (when seed (mt-set-seed o seed))))User just need to set the slots
set-seed!
and read-random!
. Then
other process is done by lower layer.
Following describes the meaning of these slots.
The slot set-seed!
requires a procedure which accepts 2 arguments,
target pseudo random and seed. seed must be bytevector.
The slot read-random!
requires a pseudo which accepts 3 arguments,
target pseudo random buffer and bytes. buffer must be a
bytevector and have bigger size than given bytes. bytes must be
a non negative fixnum.
NOTE: The custom pseudo random interface has been changed since version 0.3.6.
Make sure which version of Sagittarius your application using.
hash
procedure generates digest from given bytevector bv
according to the given algorithm. The result digest will be a bytevector.
If type is not a hash algorithm object nor predefined hash algorithm,
then options will be passed to the custom hash algorithm creation.
hash-size
procedure returns.
Flushes stored hash result in hash-algorithm into out.
Once this procedure is called hash-algorithm's state will be changed. If
you want to reuse it, you need to call hash-init!
.
Optional arguments start and end specifies the offset of
output bytevector.
(import (rnrs) (sagittarius) (math) (clos user)) ;; hash operations (define (foo-init hash) #t) (define (foo-process hash bv) (let ((len (bytevector-length bv))) (bytevector-copy! bv 0 (slot-ref hash 'buffer) 0 (min len 16)))) (define (foo-done hash out) (let ((v (integer->bytevector (equal-hash (slot-ref hash 'buffer))))) (bytevector-copy! v 0 out 0 (min 8 (bytevector-length v))))) (define-class <foo-hash> (<user-hash-algorithm>) ((buffer :init-form (make-bytevector 16)))) (define-method initialize ((o <foo-hash>) initargs) (call-next-method) (slot-set! o 'init foo-init) (slot-set! o 'process foo-process) (slot-set! o 'done foo-done) (slot-set! o 'block-size 16) (slot-set! o 'hash-size 8) (slot-set! o 'oid #f) (slot-set! o 'state #f)) ;; marker (define-class <foo-marker> () ()) (define FOO (make <foo-marker>)) (register-hash FOO <foo-hash>) ;; use with APIs (hash FOO (string->utf8 "hash")) ;; -> #vu8(245 221 54 232 0 0 0 0)The slots
init
, process
and done
must be set with a
procedure which will be called by hash-init!
, hash-process!
and
hash-done!
respectively.
The procedure set to process
and done
must accept 2 or 4
arguments. If it can accept 4 arguments, then optional argumens start
and end are passed. Implementation can use these information to
ptimise memory allocation. If it can accept 2 argumens, then framework
handles the range. In this case, uneccesarry allocation may happen.
The slots block-size
and hash-size
must be non negative exact
integer and will be returned by hash-block-size
and hash-size
procedures respectively.
The slot oid
must be set #f or string which represent OID of the custom
hash algorithm. If you don't have it, it's better to set #f.
The slot state
can be anything, this slot is for storing the hash state
if you need.
1 <= p <= 251
.
Keyword argument prng specifies which pseudo random uses to find a prime
number.
mod-inverse
defined in (sagittarius)
library.mod-expt
defined in (sagittarius)
library.(import (rnrs) (net mq amqp api)) ;; Sends text message to SAMPLE.QUEUE on localhost:5672 (call-with-amqp-connection "localhost" "5672" (lambda (conn) (call-with-amqp-session conn (lambda (session) (let ((sender (create-amqp-sender session "SAMPLE.QUEUE")) (message (create-amqp-text-message "Hello AMQP!!"))) (send-amqp-message sender message) (destroy-amqp-sender sender)))))) ;; Receives text message from SAMPLE.QUEUE on localhost:5672 (call-with-amqp-connection "localhost" "5672" (lambda (conn) (call-with-amqp-session conn (lambda (session) (let* ((receiver (create-amqp-receiver session "SAMPLE.QUEUE")) (message (receive-amqp-message receiver) (destroy-amqp-sender receiver) message)))))))
(import (rnrs) (net mq mqtt)) (let ((conn (open-mqtt-connection "localhost" "1883"))) ;; subscribes to "topic" topic with accepting QoS exactly once (mqtt-subscribe conn "topic" +qos-exactly-once+ (lambda (topic payload) (let ((msg (get-bytevector-all payload))) (cond ((not (eof-object? msg)) (print (utf8->string msg)) (string=? (utf8->string msg) "END")) (else #f))))) (let loop () ;; receives until "END" message was sent (unless (mqtt-receive-message conn) (loop))) ;; unsubscribe from "topic" (mqtt-unsubscribe conn "topic") (close-mqtt-connection! conn))
(import (rnrs) (net mq mqtt)) (let ((conn (open-mqtt-connection "localhost" "1883"))) ;; publish message to "topic" topic. (mqtt-publish conn "topic" (string->utf8 "Hello MQTT")) (close-mqtt-connection! conn))
+mqtt-3.1.1+
.
This procedure is for future extension such as supporting websocket.
mqtt-receive-message
.
+qos-at-most-once+
.
(import (rnrs) (net mq mqtt broker)) ;; Wait on port 9000 (define broker (make-mqtt-broker "9000"))) ;; start the broker. (mqtt-broker-start! broker)
<simple-server>
.
If config keyword argument is specified, the value must be an
configuration object created by make-mqtt-broker-config
, then the
specified configuration is used. Otherwise default configuration
which can be created by (make-mqtt-broker-config)
is used.
If authentication-handler keyword argument is specified, then
the specified value which must be a procedure takes 2 arguments, username
and password, handles authentication. If the procedure doesn't return
true value then authentication error packet is sent to the client.
<server-config>
with
:non-blocking?
option.
server-start!
and
server-stop!
.
(import (rnrs) (net oauth) (sagittarius control) (srfi :13 strings)) ;; obtain a request token. ;; type consumer key and secret you have got issued by Twitter (define token (obtain-request-token "http://api.twitter.com/oauth/request_token" (make-consumer-token :key "consumer key" :secret "consumer secret"))) (define (get-pin url) (print "Open the following url and type in the shown PIN.") (print url) (let loop () (display "Input PIN: ") (flush-output-port (current-output-port)) (let1 pin (get-line (current-input-port)) (cond ((eof-object? pin) #f) ((string-null? pin) (loop)) (else pin))))) (define (report token) (print "(begin") (print " (define consumer-key \"" (token-key (token-consumer token)) "\")") (print " (define consumer-secret \"" (token-secret (token-consumer token))"\")") (print " (define access-token \""(token-key token)"\")") (print " (define access-token-secret \""(token-secret token)"\")") (print ")")) (define (main args) (let1 pin (get-pin (make-authorization-uri "http://api.twitter.com/oauth/authorize" token)) ;; authorize the request token manually. (authorize-request-token token pin) ;; obtain the access token (let1 access-token (obtain-access-token "http://api.twitter.com/oauth/access_token" token) (report access-token))))Now you get the access token to tweet, let's tweet something on Sagittarius:
(import (rnrs) (srfi :26 cut) (text sxml ssax) (net oauth) (sagittarius io)) (define consumer-key "your consumer key") (define consumer-secret "your consumer secret") (define access-token "your access token") (define access-token-secret "your access token secret") ;; creates an access token to tweet. (define access-token (make-access-token :key access-token :secret access-token-secret :consumer (make-consumer-token :key consumer-key :secret consumer-secret))) (define (call/twitter-api->sxml token method path params . opts) (define (call) (access-protected-resource (string-append "http://api.twitter.com" path) token :request-method method :user-parameters params)) (define (retrieve body status hint advice) (if hint (print hint)) (if advice (print advice)) (call-with-input-string body (cut ssax:xml->sxml <> '()))) (call-with-values call retrieve)) (define (twitter-update/sxml token message . opts) (call/twitter-api->sxml token 'POST "/1/statuses/update.xml" `(("status" ,message)))) ;; if you want to use this from command line. (import (getopt)) (define (main args) (with-args args ((message (#\m "message") #t (usage))) (print (twitter-update/sxml access-token message))))The examples explain basic flows. To obtain an access token, and access to protected resource with it.
POST
or query string if the request-method is GET
.
timestamp specifies timestamp to send to the server.
auth-location specifies the place where the authentication information
located. This can be either :header
or :parameters
.
request-method specifies which request method is used. This can be either
GET
or POST
. POST
is recommended.
callback-uri specifies call back uri described in OAuth specification. If
users don't use specific location to be redirected, this must not be specified.
additional-headers is alist of additional header to be sent to the server.
signature-method specifies which hash method is used. For now we only
support :hmac-sha1
.
error-translator specifies how to treat the error message sent by the
server when error occurred. This must be a procedure which accepts 3 arguments,
http status, headers and body respectively.
obtain-request-token
.
Creates a authorization URI which user must agree.
The other keyword arguments are the same as obtain-request-token
.
obtain-request-token
.
verificateion-code must be a string returned by the URI generated by the
procedure make-authorization-uri
Sets the given verificateion-code to the request token and authorized flag
#t, manually.
obtain-request-token
.
obtain-access-token
or created by make-access-token
.
Accesses to protected resource.
The keyword argument on-refresh is a hook for when token is expired and
refreshed. It must accept be a procedure which accepts 1 argument that is a
refreshed access token.
The rest keyword arguments are the same as the obtain-request-token
.
(import (net server) (sagittarius socket)) (define (handler server socket) ;; echo message is limited to 255 bytes in this example (let ((r (socket-recv socket 255))) ;; socket will be closed by the framework (socket-send socket r))) (define server (make-simple-server "5000" handler)) (server-start! server)Above example creates only one thread and if there are more than one connection, then the latter one needs to wait until first one is done. The library also provides mult threading server. Following example describes how to make multi threading server.
(import (net server) (sagittarius socket)) ;; specifies maximum thread number (define server-config (make-server-config :max-thread 5)) (define (handler server socket) (let ((r (socket-recv socket 255))) ;; socket will be closed by the framework (socket-send socket r))) (define server (make-simple-server "5000" handler :config server-config)) (server-start! server)If the server gets more than 5 connection simultaneously, then it tries to wait until one of the connection's task finishes. If it doesn't finish in time, then connection will be refused. If clients keep the connection but server wants to handle requests more than configured thread number, then specify non-blocking? keyword argument with #t.
(import (net server) (sagittarius socket)) ;; specifies maximum thread number (define server-config (make-server-config :max-thread 5 :non-blocking? #t)) (define (handler server socket) (let ((r (socket-recv socket 255))) (if (eof-object? r) ;; close the socket after the process (socket-close socket) (socket-send socket r)))) (define server (make-simple-server "5000" handler :config server-config)) (server-start! server)Above server example creates 5 threads and accept all requests. The requests are dispatched to the least busy thread. There are couple of restrictions to use this server. See the descirption of non-blocking? keyword argument.
<simple-server>
,
otherwise #f.<simple-server>
, then the procedure uses the class to
instantiate. And during instantiation, given other keys are passed.
Keyword argument config is specified, it must be an instance
of <server-config> or subclass of it, then the server is created
according to the configuration.
on-server-start!
.
NOTE: Server object is not reusable thus once server is started, it is
impossible to restart the server.
on-server-stop!
.
<server-config>
,
otherwise #f.make-server-tls-socket
. It is strongly recommended to
specify this keyword argument, otherwise key exchange is done
anonymously, means no signature is sent.
&assertion
is signaled.
create-odbc-env
.
server must be a string indicating ODBC database name.
username and password must be string.
Connects to server with authentication of username and
password and returns ODBC database connection object. If optional
argument auto-commit is #f then the connection won't commit transaction
automatically.
server
keyword.
Following DSN is connecting foo database configured in ODBC.
"dbi:odbc:server=foo"
The dbi-connect
supports :username
, :password
and
:auto-commit
keyword arguments. The detail about DBI see
(dbi) - Database independent access layer.
calc:expr
. This parser accepts one
argument which is a lazy sequence provided by SRFI-127 (srfi :127)
,
and returns 3 values, parse state, parser value and next input.
NOTE: A lazy sequence is a pair, whose cdr
part might be a generator.
A normal pair can also be a lazy sequence.
(import (rnrs) (peg) (peg chars) (srfi :14 char-sets) (srfi :121 generators) (srfi :127 lseqs)) (define ascii-digits (char-set-intersection char-set:digit char-set:ascii)) (define calc:num ($do (s ($optional ($or ($eqv? #\+) ($eqv? #\-)) #\+)) (n ($many ($char-set-contains? ascii-digits) 1)) ($return (string->number (apply string s n))))) (define (calc:op c) ($seq ($many ($satisfy char-whitespace?)) ($eqv? c) ($many ($satisfy char-whitespace?)))) (define calc:+ (calc:op #\+)) (define calc:* (calc:op #\*)) (define calc:open (calc:op #\()) (define calc:close (calc:op #\))) (define calc:simple ($or ($do calc:open (a ($lazy calc:expr)) calc:close ($return a)) calc:num)) (define calc:mulexp ($or ($do (a calc:simple) calc:* (b calc:simple) ($return (* a b))) calc:simple)) (define calc:expr ($or ($do (a calc:mulexp) calc:+ (b calc:mulexp) ($return (+ a b))) calc:mulexp))The parser can be called like this:
(calc:expr (generator->lseq (string->generator "1 + 2")))=> #<parse-succcess> 3 '()
(calc:expr (generator->lseq (string->generator "1 - 2")))=> #<parse-succcess> 1 '(#space #- #space #2)
()
or not.
NOTE: An input of parsers, which is lazy sequence, doesn't necessarily be a
character sequence. So users can implmenet own lexer.
NOTE2: The above example of the parser usage can also be like this:
(calc:expr (string->list "1 + 2"))=> #<parse-succcess> 3 '()
+parse-success+
- Indicating successful parse result+parse-fail+
- Indicating failure parse result+parse-expect+
- Indicating different from expected input+parse-unexpect+
- Indicating unexpectedly matched input+parse-fail+
and
return value is given message.
+parse-expect+
and
return value is given message.
+parse-expect+
as its state.
+parse-expect+
.
If the second form is used, then the message is returned when
the pred returned #f
.
+parse-unexpect+
,
otherwise return successful and #f
as its returning value.
+parse-expect+
is returned.
+parse-expect+
is returned.
If one of the parser returns +parse-fail+
, then the entire parser
returned by this procedure fails. For example, the parser after the
$fail
won't be evaluated.
($or ($satisfy char-whitespace?) ($fail "Boom!") ($satisfy char-lower-case?))
+parse-expect+
.
at-most specifies the number of maximum parse. If the parser
parsed at-most input, then it returns successful even the
rest of the input contains the valid input of the given parser.
eqv?
.
If the comparison result is #t
, then it returns successful.
This procedure is equivalent with the following:
#f
.
If the second form is used, then fallback is returned when the
parser returned non successful.
$bind
is useful to take the result of the parsers.
This procedure is used to implement $do
described below.
$do
macro makes users easier to bind variables. The syntax is
the following:
$do ::= ($do clause ... parser) clause ::= (var parser) | (parser) | parserThe following example shows how to bind a variable returned by the
$many
procedure.
($do (c* ($many ($satisfy char-numeric?))) ($return (string->number (list->string c*))))The above parser parses given numeric character sequence and returns a number. The c* is the result of the $many.
$lazy
macro delays the creation of parser. This macro is
useful to handle cross reference. For example:
(define a ($do (c b) ($return c))) (define b ($do (c a) ($return c)))The above code causes unbound variable in runtime when the definition of
a
is evaluated. To avoid this, users can use the $lazy
like this:
(define a ($do (c ($lazy b)) ($return c))) (define b ($do (c a) ($return c)))
($if #t ($eqv? #\t) ($eqv? #\f)) ;; ($eqv? #\t) will ba calledThe
$if
can be used to dispatch parsers by the results like this:
($do (c ($optional ($eqv? #\t))) ($if c ($return c) ($return 'something)))
clause ::= (pred parser)The parser returned by this macro is similar with the one from
$if
,
the difference is this macro can handle multiple predicates.
$when
macro returns a parser which calls the given parser
only if the pred returned true value.
The $unless
macro returns a parser which calls the given parser
only if the pred returned #f
.
They are defined like this:
(define-syntax $when (syntax-rules () ((_ pred body) ($if pred body ($fail 'pred))))) (define-syntax $unless (syntax-rules () ((_ pred body) ($when (not pred) body))))
$parameterize
macro returns a parser which calls the given
parser in the extended dynamic extend with the given bindings.
The bindings must be the following form:
bindings ::= ((parameter value) ...)
$guard
macro returns a parser which is wrapped by the guard
.
When the given parser raises an error during parsing, then the
guard-clause will be executed.
The guard-clause must be the following form:
guard-clause ::= (variable (pred clause) ...)
The pred must be a expression which checks if the raised condition
should be handled by the coupled clause or not. If the pred
is evaluated to true value, then the coupled clause is called with
the input of the given parser.
(peg)
can be used for all kinds of
input. This section describes parsers which can only be used for character
input.
(define ($char-set-contains? s) ($satisfy (lambda (c) (char-set-contains? s c)) s))
(define ($token s) (apply $seq (map $eqv? (string->list s))))
(import (rnrs) (crypto) (rsa pkcs :5)) (define salt (string->utf8 "salt")) (define iteration-count 1024) (define pbe-parameter (make-pbe-parameter salt iteration-count)) (define pbe-key (generate-secret-key pbe-with-sha1-and-des "password")) (define pbe-cipher (cipher pbe-with-sha1-and-des pbe-key :parameter pbe-parameter)) (encrypt pbe-cipher (string->utf8 "This is an example.")) ;; -> #vu8(254 229 155 168 167 192 249 43 33 192 161 215 28 117 ;; 169 129 147 60 16 52 235 79 90 23) (decrypt pbe-cipher #vu8(254 229 155 168 167 192 249 43 33 192 161 215 28 117 169 129 147 60 16 52 235 79 90 23)) ;; -> #vu8(84 104 105 115 32 105 115 32 97 110 32 101 120 97 ;; 109 112 108 101 46)The library itself defines simply its cipher and key generate methods. Hence user can use it with (crypto) library (see (crypto) - Cryptographic library) NOTE: Currently the library only supports encryption and decryption, not MAC generation nor verification. NOTE: When you create cipher object with PBE related algorithms, the you need to pass
:parameter
keyword to cipher
procedure, otherwise raises
an error.
pbe-with-md5-and-des
uses MD5 hash and DES algorithm.
<user-hash-algorithm>
describes in
Custom hash algorithm. The default is HMAC and if you
don't have any reasonable reason, this must not be changed.
pbkdf-1
and pbkdf-2
.
This procedure just calls given kdf with given arguments and returns
derived key bytevector.
<pbe-secret-key>
. parameter must be subclss of
<pbe-parameter>
.
This method is called in the initialize
method of
<pbe-cipher-spi>
and must return 2 values; the first one is derived key
as bytevector and second one is initial vector as bytevector.
The PKCS#5 encryption and decryption procedures require to derive both
key and initial vector from given password and parameter (salt and iteration
count). This method is used in PBE cipher to derive key and initial vector.
The purpose of this method is to re-use <pbe-cipher-spi>
. For example,
PKCS#12 can use this cipher, however it requires different key derivation
mechanism.
(import (rnrs) (clos user) (rfc hmac) (math)) (define-class <pbkef2-with-hmac-sha1-des3> () ()) (define pbkdf2-with-hmac-sha1-des3 (make <pbkef2-with-hmac-sha1-des3>)) (define-method generate-secret-key ((mark <pbkef2-with-hmac-sha1-des3>) (password <string>)) (make <pbe-secret-key> :password password :hash (hash-algorithm HMAC) :scheme DES3 :iv-size 8 :length 24 :type PKCS5-S2)) (register-spi pbkdf2-with-hmac-sha1-des3 <pbe-cipher-spi>)And using this supported PBES2 cipher is like this;
(let* ((param (make-pbe-parameter (string->utf8 "saltsalt") 1024)) (key (generate-secret-key pbkdf2-with-hmac-sha1-des3 "password")) (pbe-cipher (cipher pbkdf2-with-hmac-sha1-des3 key :parameter param)) (ciphertext (encrypt pbe-cipher (string->utf8 "This is an example.")))) (utf8->string (decrypt pbe-cipher ciphertext)))I suppose this is correct, but I could not find any implementation which supports PBES2. I usually test with JCE, so if you have some recommendation, please let me know.
(import (rnrs) (rsa pkcs :12)) (define keystore (load-pkcs12-keystore-file "keystore.p12" "pass")) (pkcs12-keystore-get-key keystore "key-name" "key-pass") ;; -> <private-key> (pkcs12-keystore-get-certificate keystore "cert-name") ;; -> <x509-certificate> ;; certs are list of X509 certificate associated with given private-key (pkcs12-keystore-set-key! keystore "key-name2" private-key "key-pass2" certs) ;; cert must be an X509 certificate (pkcs12-keystore-set-certificate! keystore "cert-name2" cert) (store-pkcs12-keystore-to-file keystore "keystore2.p12" "pass2")
load-pkcs12-keystore
loads from given binary input port.
The load-pkcs12-keystore-file
loads from given file.
storepass must be a string and a password for given keystore.
'()
is
returned.
alias must be a string.
store-pkcs12-keystore
writes to given binary output port
output-port.
The store-pkcs12-keystore-to-file
writes to given file file.
storepass must be a string and is used to encrypt whole contents.
<queue>
.+inf.0
.enqueue!
call. Besides, if the value of the result of
mtqueue-max-length
is positive, and adding objs makes the
number of element in queue exceeds it, an error is raised and
queue won't be modified. (If the maximum length is zero, this procedure
always fail. Use enqueue/wait!
below.)
enqueue!
, when queue is an mtqueue, all objects are added
atomically, and the value of max length is checked. See enqueue!
above
for more detail.
enqueue!
and queue-push!
, respectively, except that
these don't modify queue if it already contains objs (elements are
compared by two-argument procedure eq-proc).
When queue is an mtqueue, all objects are added atomically, and the max
length is checked. See enqueue!
above for the detail.
queue-pop!
may be used to emphasize it
works with queue-push!
.
If queue is empty, fallback is returned if give, otherwise an
error is raised.
If queue is mtqueue and its max length is zero, then the queue is
always empty. Use dequeue/wait!
to use such a queue as a
synchronisation device.
queue->list
below.
<queue>
by giving the class to the
optional class arguments. The optional initargs arguments are
passed to the constructor of class.
dequeue-all!
, the content of queue remains intact.
The returning list is a copy of the content. So modifying the list won't
affect queue.
enqueue/wait!
and queue-push/wait!), or the mtqueue is empty
(for dequeue/wait!
and queue-pop/wait!). The blocked caller
thread is unblocked either the blocking condition is resolved, or the
timeout condition is met.
The optional timeout argument specifies the timeout condition. If it
is #f, those procedure wait indefinitely. If it is a real number, they wait
at least the given number of seconds.
In case the call is blocked then timed out, the value of timeout-val is
returned, which default value is #t.
When enqueue/wait!
and queue-push/wait!
succeeds without hitting
timeout, they return #t.
((name body) ...)name ... are the field names and body ... are the correspoinding field body. Both are as string. Field names are converted to lower-case characters. The keyword argument strict? switches the behaviour when the procedure encounter EOF. If it's #f, then it simply ignore the field and return the composed list. And if it's #t, it raises
&rfc5322-parse-error
.
The keyword argument reader reads a line from given port. The default
is rfc5322-line-reader
and it treats both LF and CRLF eof style. If you
want to read from binary port, you need to pass own reader.
rfc5322-read-headers
.
If the field with given field-name is in header-list, the
procedure returns its value in a string. Otherwise, if default is
given, it is returned, and if not, #f is returned.
rfc5322-read-headers
.
This procedure collects all the given field-name from the
header-list. If there's no header named field-name, then the
procedure returns ()
.
(list (cons (string->char-set ":") rfc5322-quoted-string) (cons *rfc5322-atext-chars* rfc5322-dot-atom))
rfc5322-next-token
repeatedly on it until it
consumes all input, and returns a list of tokens.
dot-atom
and quoted-string
respectively.year, month, day-of-month, hour, minute, second, time-zone, day-of-week.
time-zone is an offset from UT in minutes. day-of-week is a day from
sunday, and may be #f if that information is not available. month is an
integer between 1 and 12, inclusive. If the string is not parsable, all
the elements are #f.
#\=
or not. If this is #f, then the result
value won't contain padding character.
The base64url-encode
encodes the given input to Base 64 URL safe
encoded bytevector. Which doesn't use +
and /
.
base64-encode
procedure. The default value is a transcoder with UTF-8 codec with EOL
style none.
The keyword argument padding? is the same as base64-encode
.
The base64url-encode-string
encodes the given input to Base 64 URL safe
encoded bytevector. Which doesn't use +
and /
.
base64-encode
.
The open-base64url-encode-input-port
and
open-base64url-encode-output-port
encode to Base64 URL safe encode.
base64url-decode
decodes Base64 URL safe encoded value.
base64-decode
.
The keyword argument specifies how to convert the decoded bytevector to string.
If this is #f, the procedure returns raw bytevector.
The base64url-decode-string
decodes Base64 URL safe encoded value.
open-base64url-decode-input-port
and
open-base64url-decode-output-port
decode Base64 URL safe encoded
value.
(import (rnrs) (rfc cmac) (math) (crypto)) (define K (generate-secret-key AES (integer->bytevector #x2b7e151628aed2a6abf7158809cf4f3c))) (define aes-cipher (cipher AES K)) (hash CMAC #vu8() :cipher aes-cipher) ;; => #vu8(187 29 105 41 233 89 55 40 127 163 125 18 155 117 103 70) ;; for AES-CMAC-96 (hash CMAC #vu8() :cipher aes-cipher :size (/ 96 8)) ;; => #vu8(187 29 105 41 233 89 55 40 127 163 125 18)The RFC is defined for only AES block cipher however the implementation can take any block cipher such as DES3. CAUTION: only AES cipher is tested.
(import (rnrs) (rfc hmac) (math)) ;; the keyword arguments can be omitted, then it will use an empty bytevector ;; as HMAC key and SHA-1 algorithm as digest algorithm. (define hmac (hash-algorithm HMAC :key (string->utf8 "hmac key") :hash SHA-1)) (hash hmac (string->utf8 "test")) ;; -> #vu8(57 255 153 118 15 133 255 73 12 199 199 115 185 32 43 225 61 254 159 94)
(import (rfc http)) (define url "http://example.com/path") (let-values (((server path) (url-server&path url))) (http-get server path)) ;; -> return 3 values ;; status ;; header ;; body
GET
, HEAD
, POST
, PUT
, and
DELETE
, respectively.
The body argument of http-post
and http-put
can be
UTF-8 string, bytevector or list of body parameters. The parameters are
used for sending multipart form data. The detail parameter form is described
in the http-compose-form-data
.
The keyword :value and file should not be represented
simultaneously, if both keywords are found then :file is used.
Optional arguments options are passed to underling procedure
http-request
.
POST
and PUT
HTTP method to send data. If it's specified then it must be a procedure
which takes three arguments, headers, encoding and header-sink.
NOTE: Users can define own receiver and sender however the API may change
in the future. So if the predefined ones are sufficient, it is safe to use
them.
The keyword arguments start with auth- handle authentication.
If the server respond status code 401
then those values are
used. auth-handler must be a procedure and takes five arguments
alist of connection-info, auth-user, auth-password, response
headers and response body. If the handler returns list of "authorization"
value then http-request
sends it as the authentication data. For
example, if the server requires BASIC authentication then the procedure
should return something like following value;
(("authorization" "Basic dXNlcjpwYXNz"))Following is the complete example of auth-handler;
(define (basic-auth-handler info user pass headers body) (let ((m (format "~a:~a" user pass))) `(("authorization" ,(format "Basic ~a" (base64-encode-string m))))))
http-request
supports BASIC authentication and Digest authentication
by default. If you know that the server requires one of each then specifying
auth-user and auth-password is sufficient.
If keyword argument secure is true value then TLS socket is used for
physical connection.
The rest arguments opts is converted to request header.
user-agent
header.
string->utf8
.
multipart/form-data
with
content of param.
The content will be created by http-compose-form-data
procedure
passing param.
(http-get "google.com" "/" :receiver (http-string-receiver))=> status headers and string representation of received content
(http-get "google.com" "/" :receiver (http-binary-receiver))=> status headers and bytevector representation of received content
(http-get "google.com" "/" :receiver (http-null-receiver))=> status headers and unspecified value
(http-get "google.com" "/" :receiver (let-values (((port extract) (open-bytevector-output-port))) (http-oport-receiver port (lambda (port size) (extract)))))=> status headers and bytevector representation of received content
content-length
header contains non
number value, then the file will be cleaned.
(http-get "google.com" "/" :receiver (http-file-receiver "google.html"))=> status headers and "google.html"
Content-Encoding
header with value gzip
, then the
receiver decodes the response and propagates to given receiver.
Otherwise, it simply forwards the response to receiver.
The following describes how to use it:
(http-get "google.com" "/" :accept-encoding "gzip" :receiver (http-gzip-receiver (http-string-receiver)))
path?composed query
form.
params must be a list of name & value list or null list.
<params> : (<params> ...) <param> : (<name> <value>) | (<name> <key> <value> <key2> <value2> ...) <key> : :value | :file | :content-type | :content-transfer-encoding | other keyword (used as a header name)<value> is the content of <name> parameter. It can be any of Scheme object however it is converted to string representation except bytevector. If :file keyword is used then it read the content of <value>.
Upgrade
header defined in HTTP/1.1. Thus
users must know if the server supports HTTP/2 or not, ahead.
(import (rfc http2)) (define conn (make-http2-client-connection "twitter.com" "443" :secure? #t)) (http2-get conn "/") ;; -> returns 2 values ;; header ;; body (close-http2-client-connection! conn)
user-agent
header. The default value is Sagittarius-
followed by version number.
NOTE: The connection does not guess if it should use secure connection or
not by looking at port number or service name. Which means, even if you
specify "https"
or "443"
however secure? keyword
argument must be passed.
NOTE2: Created connections hold opened socket.
(make-gzip-receiver)
.
If the keyword argument redirect-handler is specified, then the procedure
uses given redirect-handler to handle redirection.
http2-get
.
http2-get
.
http2-get
.
The procedure returns a list of response header and content.
(http2-gzip-receiver (http2-binary-receiver))
(rfc http)
and
(rfc http2)
library.
http-request
defined in (rfc http)
library to send an request.
http2-request
defined in (rfc http2)
library to send an request.
http-null-receiver
forwards http-null-receiver
defined
in (rfc http)
for http1-connection
and
http2-null-receiver
defined
in (rfc http2)
for http2-connection
http-oport-receiver
forwards http-oport-receiver
defined
in (rfc http)
for http1-connection
and
http2-data-receiver
defined in (rfc http2)
for
http2-connection
http-blob-sender
forwards http-blob-sender
defined
in (rfc http)
for http1-connection
and
http2-data-sender
defined in (rfc http2)
for
http2-connection
http-string-sender
forwards http-string-sender
defined
in (rfc http)
for http1-connection
and
http2-data-sender
defined in (rfc http2)
with given
string converted by string->utf8
procedure defined
for http2-connection
http-null-sender
forwards http-null-sender
defined
in (rfc http)
for http1-connection
and does nothing
for http2-connection
.
(text json pointer)
.
For more information, please see (text json pointer) - JSON Pointer
&invalid-pem-format
,
otherwise #f.:multiple
.&pre-eb-as-boundary
,
otherwise #f.multiple
builder
asn1
(asn.1)
library.
decorder
parse-pem
uses the specified
procedure to convert body of the PEM content.
If it's not specified, the procedure uses BASE64 decoding.
&invalid-pem-format
&pre-eb-as-boundary
:multiple
is #f.
For example:
-----BEGIN FOO----- ... foo value ... -----BEGIN BAR----- ... bar value... -----END BAR-----parsing PEM like above must specify
:multiple
with true value.
Otherwise, &pre-eb-as-boundary
is signaled.
parse-pem
.
hotp
is an alias of generate-hmac-based-one-time-password
.
(current-time)
.
NOTE: time keyword should not be specified unless its testing purpose.
The keyword arguments described below are system parameters, means these
parameters must be agreed between authenticator.
The keyword argument start-time is given, then it must be a UTC time
object of SRFI-19. The procedure computes returning one-time password according
to the given time. The defaule value is (make-time time-utc 0 0)
.
The keyword argument step is given, then it must be a positive exact
integer. The procedure computes returning one-time password according
to the given time. The defaule value is 30
.
The keyword argument step is given, then it must be a positive exact
integer. The procedure computes returning one-time password according
to the given time. The defaule value is 30
.
The keyword argument mode is given, then it must be a hash algorithm name
either builtin or custom. The procedure computes returning one-time password
according to the given time. The defaule value is SHA-1
.
Generates an Time-based one-time password.
totp
is an alias of generate-time-based-one-time-password
.
=0A
and =0D
respectively.
quoted-printable-encode
procedure. The default is utf-8 codec with
NONE eol style.
quoted-printable-decode
.
The keyword argument specifies how to convert the decoded bytevector to string.
If this is #f, the procedure returns raw bytevector.
(import (rfc sftp) (pp) (srfi :26)) (call-with-sftp-connection "localhost" ;; hostname "23" ;; port number (lambda (conn) ;; read directory (pp (sftp-readdir conn ".")) ;; only short names (pp (sftp-readdir-as-filenames conn ".")) ;; only long names (usually POSIX 'ls -l' format) (pp (sftp-readdir-as-longnames conn ".")) ;; retrieve a file as a bytevector (print (utf8->string (sftp-read! conn "reading/file" (sftp-binary-receiver)))) ;; store a file to local file directly (sftp-read conn "/a/file/path" (sftp-file-receiver "where/to/store" :options (file-options no-fail))) ;; upload a file (let ((handle (sftp-open conn "boo" (bitwise-ior +ssh-fxf-creat+ +ssh-fxf-write+)))) (call-with-input-file "a/local/file" (cut sftp-write! conn handle <>) :transcoder #f)) ;; rename a file (sftp-rename! conn "boo" "foo") ;; remove a file (sftp-remove! conn "foo") ;; create a directory (sftp-mkdir! conn "boo") ;; remove a directory (sftp-rmdir! conn "boo") ;; create a symbolic link (pp (sftp-symlink! conn "/tmp" "tmp")) ;; get a actual path of symbolic link (pp (sftp-readlink conn "tmp")) ;; get a real path. (usually an absolute path) (pp (sftp-realpath conn "../"))) :username "username" :password "password")
make-client-sftp-connection
.
+ssh-fxf-creat+
must be specified as well.+ssh-fxf-creat+
must be specified as well.sftp-open
.
(define (sftp-binary-receiver) (let-values (((out extract) (open-bytevector-output-port))) (lambda (offset data) (if (< offset 0) (values -1 (extract)) (values (copy-binary-port out data) #f)))))
sftp-read
.sftp-read
.
The keyword argument option must be created by file-options
.
By default no option.
sftp-read
.
sftp-opendir
or
a string indicating existing path.
Reads the given handle/path and returns the list of contents. The content
is an object of <sftp-name>
which has filename
, longname
and attribute
slots.
sftp-opendir
or
a string indicating existing path.
Calls sftp-readdir
and strips out the result object to string by
calling (slot-ref c 'filename)
or
(slot-ref c 'longname)
respectively.
(import (rnrs) (rfc client)) ;; creates SMTP mail object (define mail (smtp:mail (smtp:from "Takashi Kato" "ktakashi@ymail.com") (smtp:subject "Subject") "Message" (smtp:cc "ktakashi@ymail.com"))) ;; creates an SMTP connection (define smtp-conn (make-smtp-connection "your.smtp.server.com" "587")) ;; connect to the server (smtp-connect! smtp-conn) ;; returns SMTP connection ;; Authenticate if required. (when (smtp-authentication-required? smtp-conn) ;; NOTE: only AUTH PLAIN is supported for now (cond ((memq 'PLAIN (smtp-connection-authentication-methods smtp-conn)) (smtp-authenticate! smtp-conn (smtp-plain-authentication "username" "password"))) (else (smtp-disconnect! smtp-conn) (error #f "authentication method not supported" (smtp-connection-authentication-methods smtp-conn))))) ;; Send it (smtp-send! smtp-conn mail) ;; returns SMTP connection ;; Clean up (smtp-disconnect! smtp-conn)The followings describe how to create SMTP mail object with attachment(s) or inlined image.
;; Messae with attachment (smtp:mail (smtp:from "Takashi Kato" "ktakashi@ymail.com") (smtp:subject "Message with attachment") "Message" (smtp:to "ktakashi@ymail.com") (smtp:attachment "application" "octet-stream" (get-file-content) ;; file content suitable for this "file.odt")) ;; HTML message with inlined image. (smtp:mail (smtp:from "Takashi Kato" "ktakashi@ymail.com") (smtp:subject "HTML message with inlined image") "<html><body><img src='cid:image' /></body></html>" (smtp:to "ktakashi@ymail.com") (smtp:attachment "image" "jpeg" ;; port can also be used ;; NB: if you call smtp-mail->string twice in this case ;; then this may break. So make sure you use this ;; mail object once (includeing smtp-send!) (open-file-input-port "image/file.jpg") "image.jpg" ;; specifies content-disposition parameter "inline" ;; adding content-id of this attachment '("content-id" "<image>")) ;; make this mail HTML (smtp:header "Content-Type" "text/html"))Alternative message can be created like this:
;; Message with alternative ;; Content must not be specified otherwise raise an syntax error (smtp:mail (smtp:from "Takashi Kato" "ktakashi@ymail.com") (smtp:subject "Message with alternative") (smtp:to "ktakashi@ymail.com") (smtp:alternative ("text" "plain" "Plain text message") ("text" "html" "<html><body>HTML message</body><html>")) )
EHLO
or HELO
command parameter. Otherwise the result of
machine-name
(defined in SRFI 112) is used.
smtp-connect!
is called.
smtp-connect!
is called.
354
and next-step is specified, then the next-step
is called with smtp-connection, status and response string. The
procedure must return 2 values, next command and next-next procedure or #f.
The smtp-authenticate!
procedure stops when next-next
procedure is #f or returning response is 235
.
The following is a simple LOGIN next-step.
(define (smtp-login-authentication) (define (prompt next?) (lambda (conn status resp) (or (and (= status 334) ;; response is encoded to BASE 64 so decode it (display (base64-decode-string resp)) (flush-output-port (current-output-port)) ;; next command (either username or password) ;; must be encoded to BASE 64 (values (base64-encode-string (get-line (current-input-port))) (and next? (prompt #f)))) (values #f #f)))) (values (lambda () (values "LOGIN" #f)) (prompt #t)))
smtp-mail->string
. So if the
smtp-mail object contains an attachment with input port, then
the port position will be forwarded. Thus second call of the
smtp-mail->string
or smtp-send!
doesn't create/send
attachment message properly.
smtp-authenticate!
procedure
for PLAIN authentication.
smtp-authenticate!
procedure
for LOGIN authentication.
The rest argument date is given, all of the values must be string,
then each authentication prompt uses the given data as if it's typed by
user. If there is no data or sufficient date, then input prompt will be
shown and let user type the authentication information.
(smtp:from email)
(smtp:from name email)message-elements must be one of the following forms:
(smtp:subject subject)
(smtp:to email)
(smtp:to name email)
(smtp:cc email)
(smtp:cc name email)
(smtp:bcc email)
(smtp:bcc name email)
(smtp:attachment type subtype content)
(smtp:attachment type subtype content filename)
(smtp:attachment type subtype content filename disposition-parameter)
(smtp:attachment type subtype content filename disposition-parameter headers ...)
(smtp:alternative type subtype content)
(smtp:alternative type subtype content headers ...)
(smtp:header name value)
stringThe order of the appearance does not matter, except string which will be the content of the creating SMTP mail. Except the
smtp:subject
and
smtp:alternative
, all elements can be appear multiple times.
text/plain
content can be string, bytevector, input-port.
Optional argument filename is specified, then content-disposition
header will have filename
parameter.
Optional argument disposition-parameter is specified, then
content-disposition
header will have specified parameter. Default
values is attachment
.
Rest argument headers is specified, then the created attachment has
extra mime header. Each header must be a list which contains 2
elements, header name and value. The value part can also contain
MIME parameters.
make-smtp-attachment
.
smtp-mail-add-attachment!
and not content argument of make-smtp-mail
. To make mail
construction easier, use smtp:mail
macro.
string-ci=?
, then the old
one is overwritten.
make-client-socket
described in
(sagittarius socket).
The keyword argument prng specifies which pseudo random algorithm will
be used for generating security parameters.
The keyword argument version specifies which TLS protocol version will be
used for negotiation. However the real version will be decided by target server.
The keyword argument session is for future extension, so do not specify.
If the keyword argument handshake #f then the procedure won't do
TLS handshake after the socket creation so users must do it manually with
tls-client-handshake
procedure described below.
The keyword argument certificates is for certificate request message.
The value must be a list of x509 certificates. If the certificates argument
is null, then the procedures send empty certificate list to the server as
a response of certificate request message.
The keyword argument private-key specifies which private key is used.
The value must be private key object described in "(crypto)".
This is needed if the target server only supports RSA key exchange protocol.
make-server-socket
described in
(sagittarius socket).
The keyword arguments prng and version are the same meaning as
make-client-tls-socket
.
The keyword argument private-key is used the same as client socket.
The difference is that it is used also for Deffie-Hellman key exchange.
If this is not specified, then key exhange is done anonymously.
It is strongly recomended to specify this keyword argument.
The keyword argument authorities must be a list of x509 certificate and
if this is not empty list then the server socket will send certificate request
message to the client.
CAUTION: the authorities keyword argument currently doesn't check
the certificate signature but only issuer DN.
make-client-tls-socket
.
flags must be non negative exact integer.
Sends given bytevector to tls-socket. flags are described in
the section (sagittarius socket). The packet
will be encrypted by tls-socket.
make-client-tls-socket
.
size and flags must be non negative exact integer.
Receives decrypted packet from tls-socket. size indicates how many
octets the procedure should receive, however it might return less octet.
flags will be passed to socket-recv
.
NOTE: tls-socket have its own buffer to return the value, so that the
procedure can take size argument.
make-client-tls-socket
.
Sends close notify alert to the socket and close it.
make-client-tls-socket
.
Returns #t if the given socket is closed, otherwise #f.
NOTE: this procedure checks if session is closed. So the real socket might not
be closed yet.
make-server-tls-socket
.
Wait for an incoming connection request and returns a fresh connected client
socket.
If the keyword argument handshake is #f then the handshake must be done
by manually with tls-server-handshake
described blow.
The keyword argument raise-error will be passed to
tls-server-handshake
.
socket-peer
.
For more details, see (sagittarius socket).
socket-name
.
For more details, see (sagittarius socket).
socket-info-values
.
For more details, see (sagittarius socket).
#x0303
for TLS 1.2#x0302
for TLS 1.1#x0301
for TLS 1.0make-client-tls-socket
.
Returns input/output-port of given tls-socket.
If optional argument close? is #f then it won't close the socket when the
port is closed or GCed.
foo://example.com:8042/over/there?name=ferret#nose \_/ \______________/\_________/ \_________/ \__/ | | | | | scheme authority path query fragment | _____________________|__ / \ / \ urn:example:animal:ferret:noseauthority = [ user-info "@" ] host [ ":" port ] If given uri does not contain the part described above, it will be #f. ex)
(uri-parse "http://localhost")=> (values http #f localhost #f #f #f #f)
#x2b
('+') to #x20
('#\space').
scheme specific +- authority +- userinfo +- host +- port +- path* +- path +- query +- fragment
(template-unit)
string
(template)
(operator varaible)
character
string
(string modifier)
*
positive exact integer
(parse-uri-template "http://{domain*}/{/path}")=> (http:// ((domain *)) / (/ path))
(expand-uri-template '((#\? ("keys" *))) '#(("keys" . #(("semi" . ";") ("dot" . ".") ("comma" . ",")))))=> ?semi=%3B&dot=.&comma=%2C
<uuid>
, otherwise
#f.00000000-0000-0000-0000-000000000000
.
(*uuid-random-state*)
.
(uuid->bytevector (make-null-uuid))=> #vu8(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
(uuid->string (make-null-uuid))=> 00000000-0000-0000-0000-000000000000
(import (rnrs) (rfc websocket)) ;; Creates an WebSocket object (define websocket (make-websocket "wss://echo.websocket.org")) ;; Sets text message event handler (websocket-on-text-message websocket (lambda (ws text) (display text) (newline))) ;; Opens the WebSocket (websocket-open websocket) ;; Sends a message to endpoint (websocket-send websocket "Hello") ;; Closes the WebSocket (websocket-close websocket)
&websocket-engine
or its sub condition
shall be raised.
The keyword argument protocols are a list of sub protocols of the
creating WebSocket. If this is set, then handshake will send it with
Sec-WebSocket-Protocol
header or equivalent.
The keyword argument extensions are a list of extensions of the
creating WebSocket. If this is set, then handshake will send it with
Sec-WebSocket-Extensions
header or equivalent.
The keyword argument engine is a type of handshake engine and
must be a symbol. This determines which handshake protocol it should
use. The default value is http
which uses HTTP/1.1.
&websocket-engine
or its sub condition
shall be raised.
After successfull call of this procedure, the websocket has a
message dispatcher thread.
websocket-open
.
The keyword argument status is specified, it must be a non
negative integer which has less then or equal to 16 bits length, then
the procedure sends it as a connection close code.
The keyword argument message is specified, must be a string, then
the procedure sends it as a connection close message. This is sent only
if the status is specified otherwise ignored.
The keyword argument timeout is used as a timeout period for waiting
underlying dispatcher thread. If the thread didn't finish in the specified
period, then it'd be terminated and &websocket-close-timeout
is
raised.
If the underlying thread raised an &uncaught-exception
, then the
procedure raises its reason.
websocket-send-text
is used.
If the data is a bytevector, then websocket-send-binary
is used.
If the data is not one of the aboves, then &assertion
is raised.
&websocket-pong
is raised.
The optional argument timeout specifies how long the procedure waits
the pong response.
The optional argument timeout-value is an alternative value when
the endpoint didn't return pong in time.
CAUTION: this procedure depends on the endpoint's behaviour.
websocket-send
. The other one is passive situation
such as receiving frame from endpoint. The first case, all active procedures
would catch &websocket
and its sub conditions. If the condition is
&websocket-engine
or its sub condition, then the condition is
re-raised. Other &websocket
conditions are not re-raised by the
APIs. Other conditions are simply re-raised without invcating event handler.
On the second case, it's mostly the same, but when
&websocket-closed
is raised, then event handler won't be invoked.
&websocket
, then the dispatcher thread opened by
websocket-open
stops running.
The procedure returns websocket.
pong-queue
of the connection.
This procedure doesn't return ping and pong control frame.
websocket-receive
is implemented on top of this procedure
like this:
(define (websocket-receive conn :key (push-pong? #f)) (define (convert opcode data) (if (eqv? opcode +websocket-text-frame+) (values opcode (utf8->string data)) (values opcode data))) (let-values (((out extract) (open-bytevector-output-port))) (websocket-receive-fragments conn (lambda (fin? opcode data) (put-bytevector out data) (if fin? (convert opcode (extract)) (values opcode #f))) :push-pong? push-pong?)))
&websocket
is a base condition of the WebSocket library's condition.
The hierarchy is the following:
+ &error + &websocket + &websocket-engine + &websocket-engine-not-found - engine - reason + &websocket-engine-scheme - scheme + &websocket-engine-connection - host - port + &websocket-closed - status - message + &websocket-pong - pong-data + &websocket-close-timeoutThe condition types are not exported by the library.
verify
described below.
<public-key>
described in the section
(crypto) - Cryptographic library.
verify
procedure in (crypto)
library. The
keyword arguments will be passed to it. For more detail, see
(crypto) - Cryptographic library.
&assertion
.
&error
.
This condition is raised when zlib process is finished unsuccessfully. You can
obtain the cause z-stream with the condition-zlib-stream
procedure and
get the detail message with the zlib-error-message
procedure. When error
occurred, however, it is raised with message-condition
and it has the
error message with. So you can simply get it with condition-message
procedure.
open-inflating-input-port
creates a custom binary input port, which
reads compressed binary data from the given port source and decompresses
the read data. When source port supports both port-position
and
set-port-position!
then the procedure will set source position
to offset of used bytes length when the created custom port is being closed.
Thus if the source port contains mixture of deflated data and non
deflated data then the custom port will only read deflated data and won't
forward the original port position beyond it no matter how big the
buffer-size is specified.
The meaning of buffer-size is the same as
open-deflating-output-port
.
The meaning of window-bits is almost the same, except if a value increased
by 32 is given, the inflating port automatically detecs whether the source
stream is zlib or gzip by its header.
If the input data is compressed with specified dictionary, the same dictionary
must be given to dictionary argument. Otherwise &zlib-error condition is
raised.
open-inflating-input-port
or
open-deflating-output-port
to inflate/deflate.
The opts will be passed to underlying procedures.
http-request
procedure.
POST
application/octet-stream
http-blob-sender
with marshalled requesthttp-binary-receiver
rpc-http-unmarshall-message
.
Default implementation returns given request itselfrpc-unmarshall-message
.(import (rnrs) (rpc json) (rpc transport http)) (define (json-rpc-send&request url method param) (let ((request (make-json-request method :param param))) (let-values (((status header response) (rpc-http-request url request))) ;; rpc-http-request unmarshalls only when HTTP status starts with "2" ;; for this example we don't check it. (json-response-result response)))) (json-rpc-send&request "http://localhost/json-rpc" "sample" "parameter") ;; -> result of method execution
make-json-request
,
json-string->json-request
or json-string->json-response
. Users
should not create an instance directly using make
.
<json-request>
and <json-response>
respectively.
params
field of the JSON
RPC protocol.
The keyword argument id is the id
field of the JSON RPC protocol.
If this is not specified then a value generated by UUID v4 will be used.
(rpc http transport)
.
When we support other transport, this implementation may change.
application/json
content type header valuejson
symbol.(import (security keystore)) (define keystore (load-keystore 'jks "keystore.jks" "storepass")) (keystore-get-key keystore "key-name" "key-pass") ;; -> <private-key> (keystore-get-certificate keystore "cert-name") ;; -> <x509-certificate> ;; certs must be a list of certificates (keystore-set-key! keystore "key-name2" private-key "key-pass2" certs) (keystore-set-certificate! keystore "cert-name2" cert) (store-keystore-to-file keystore "keystore2.jks" "storepass2")
load-keystore
loads from given binary input port input-port.
load-keystore-file
loads from given file file.
pkcs12
, jks
and jceks
are supported.
store-keystore
shall write to given binary output port
output-port.
The store-keystore-to-file
shall write to given file file.
storepass shall be a string and may or may not be used to encrypt
whole contents.
csv->list
described below.
alist := (header{0,1} record*) header := (:header value*) record := (:record value*) value := stringNote: the value returning from
csv-records
or csv-header
do not
have meta values :record
and :header
.
(make <csv>). Make sure, you import
(clos user)
library.
:record
keyword in the first element of the list.:header
keyword in the first element of the
list.html-escape
reads the string from optional argument in which
must be an textual input port and returns an escaped string.
The html-escape-string
takes a string and returns an escaped string.
:html-5
:html-4.01-strict :html-4.01, :strict, :html-strict
:html-4.01-transitional :html-transitional, :transitional
:xhtml-1.0-strict :xhtml-1.0
:xhtml-1.0-transitional
:xhtml-1.0-frameset
:xhtml-1.1
a abbr address area article aside audio b base bdi bdo blockquote body br button canvas caption cite code col colgroup command datalist dd del details dfn div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li link map mark menu meta meter nav noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbrThe result of these functions is a tree of text segments, which can be written out to a port by
write-tree
or can be converted to a string by
tree->string
(text tree) - Lightweight text generation.
You can specify attributes of the element by using a keyword-value notation
before the actual content.
(tree->string (html:a :href "http://example.com" "example"))=> <a href="http://example.com">example</a>
(tree->string (html:table :border #t))=> <table border></table>
(tree->string (html:table :border #f))=> <table></table>
(tree->string (html:div :foo "<>&\"" "<not escaped>"))=> <div foo="<>&""><not escaped></div>
'vector
or 'alist
. The first one is compatible with Chicken
Scheme's json module, the latter one is compatible with Gauche's
rfc.json
module. By default, it's set to vector
for backward
compatibility.
Conversion rules for vector
:
JSON array <-> list
JSON map <-> vector
JSON boolean <-> boolean
JSON null <-> symbol null
Conversion rules for alist
:
JSON array <-> vector
JSON map <-> alist
JSON boolean <-> boolean
JSON null <-> symbol null
This parameter affects the read and write procedures.
json-object-builder
macro.
(@ ->array spec)
(@ ->array)
(ctr mapping ...)
ctr/builder
list
or vector
.
ctr must be a procedure which accepts the same number of the
specified keys in the mapping and constucts object.
ctr/builder must be either object constructor described above
or JSON object builder created by the json-object-builder
.
If the first 2 form is used, then the created builder handles JSON
array.
If the 3rd form is used, then the created builder handles JSON object
(a.k.a map).
If the lsst form is used, then the created builder handles simple
JSON values, such as JSON string and number.
The mapping must be one of the followings:
(? key default spec)
(? key default)
(key spec)
key
(json-object-builder (make-image-holder ("Image" (make-image "Width" "Height" "Title" ("Thumbnail" (make-thumbnail "Url" "Height" "Width")) "Animated" ("IDs" ( list)))))) #| Above construct Scheme object from JSON like the following: { "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": 100 }, "Animated" : false, "IDs": [116, 943, 234, 38793] } } |#
(json-object-builder ( list (make-location "precision" "Latitude" "Longitude" (? "Address" #f) "City" "State" "Zip" "Country"))) #| Above construct Scheme object from JSON like the following: [ { "precision": "zip", "Latitude": 37.7668, "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", "Zip": "94107", "Country": "US" }, { "precision": "zip", "Latitude": 37.371991, "Longitude": -122.026020, "City": "SUNNYVALE", "State": "CA", "Zip": "94085", "Country": "US" } ] |#
*json-map-type*
parameter.
(let ((json-string "{\"bar\": {\"buz\": 1}}")) (define-record-type foo (fields bar)) (define-record-type bar (fields buz)) (define bar-builder (json-object-builder (make-bar "buz"))) (define builder (json-object-builder (make-foo ("bar" bar-builder)))) (json-string->object json-string builder))=> foo
json-object-serializer
macro.
(-> car cdr null? spec)
(-> car cdr null?)
(-> spec)
(->)
(@ ref length spec)
(@ ref length)
(@ spec)
(@)
(mapping mapping* ...)
converter/serializer
->
indicates that the given object is a listlike object which can
be accessed sequentially. car, cdr and null? specifies
how to retrieve the car part and cdr part, and how to check if the object
is empty or not, respectively. If these are not given then the macro
uses car
, cdr
and null?
.
indicates that the given object is a vectorlike object which
can be accessed randomly. ref and length specifies how to access
the element of the object, and how to retrieve the length of the object,
respectively. If these are not given then the macro uses vector-ref
,
and vector-length
.
If both of the form don't have spec
, then the macro uses the given
value.
mapping
must be one of the followings:
(? name absent ref spec)
(? name absent ref)
(name ref spec)
(name ref)
?
indicates that referencing object might be absent.
name must be a string which represents JSON object's key.
absent must be an object indicating absent value. If the converting
object is equal to this value in sense of equal?
, then the constructed
JSON representaion don't have name.
ref must be a accessor which is a procedure accepts one argument.
converter/serializer must be either a JSON object serializer or
a procedure which accepts one argument and returns JSON representaion.
(json-object-serializer (-> (("precision" location-precision) ("Latitude" location-latitude) ("Longitude" location-longitude) (? "Address" #f location-address) ("City" location-city) ("State" location-state) ("Zip" location-zip) ("Country" location-country)))) ;; Above constructs JSON representaion from the following record type. (define-record-type location (fields precision latitude longitude address city state zip country))
(json-object-serializer (("Image" image-holder-image (("Width" image-width) ("Height" image-height) ("Title" image-title) ("Thumbnail" image-thumbnail (("Url" thumbnail-url) ("Height" thumbnail-height) ("Width" thumbnail-width))) ("Animated" image-animated) ("IDs" image-ids (->)))))) ;; Above constructs JSON representaion from the following record type. (define-record-type image-holder (fields image)) (define-record-type image (fields width height title thumbnail animated ids)) (define-record-type thumbnail (fields url height width))
'vector
representaion.
(import (rnrs) (text json jmespath)) ((jmespath "a") '#(("a" . "foo") ("b" . "bar") ("c" . "baz")))=> foo
&jmespath
.
jmespath
procedure or the procedure returned by the jmespath
procedure.
The library doesn't export the condition type itself. (e.g. &jmespath
isn't exported from the library). However for the comprehensivity, we
also describe the hierarchy of the conditions here:
+ &error (standard R6RS error) + &jmespath + &jmespath:parse + &jmespath:expression - expression - argument + &jmespath:compile + &jmespath:runtimeThe
&jmespath
is the root condition. This condition itself won't be
raised.
The &jmespath:parse
is the condition raised by the parser. This means
either the given expression is lexically incorrect or grammartically incorrect.
The &jmespath:expression
is the base condition of both
&jmespath:compile
and &jmespath:runtime
. This condition itself
won't be raised.
The &jmespath:compile
is the condition raised by the compiler. This means
the parsed expression is syntatically incorrect.
The &jmespath:runtime
is the condition raised by the returned procedure.
This means evaluation error. For example, a string is passed to the avg
function.
&jmespath
,
otherwise #f.
&jmespath:parse
,
otherwise #f.
The &jmespath:parse
is a sub condition of &jmespath
.
expression
field of the given jmespath-error.
The the given jmespath-error must be a sub condition of
&jmespath:expression
.
arguments
field of the given jmespath-error.
The the given jmespath-error must be a sub condition of
&jmespath:expression
.
&jmespath:compile
,
otherwise #f.
The &jmespath:compile
is a sub condition of &jmespath:expression
.
&jmespath:runtime
,
otherwise #f.
The &jmespath:runtime
is a sub condition of &jmespath:expression
.
((jmespath "*.bar.parent(@)") '#(("foo" . #(("bar" . 1)))))=> '(#((bar . 1)))
null
.
((jmespath "parent(`{}`)") '#(("foo" . #(("bar" . 1)))))=> 'null
((jmespath "unique(@)") '(1 2 1 2 3))=> '(1 2 3)
&jmespath:runtime
if the give array is not an array.
((jmespath "is_odd(@)") '5)=> #t
&jmespath:runtime
if the give number is not a number.
((jmespath "is_even(@)") '5)=> #t
&jmespath:runtime
if the give number is not a number.
@
is passed to the expr, then the receiving
value is one of the elements of the array/object.
This function can be used like this:
((jmespath "remove(@, &odd(@))") '(1 2 3 4 5))=> '(1 3 5)
&jmespath:runtime
if the give array/object is not
either an array or object, or if the given expr is not a function
reference.
((jmespath "remove_entry(@, `[\"key2\"]`)") '#(("key" . 1)))=> '#((key . 1))
((jmespath "remove_entry(@, &contains(`[\"key2\"]`, @))") '#(("key" . 1) ("key2" . 2)))=> '#((key . 1))
&jmespath:runtime
if the give object is not an object,
or if the given array/expr is not an array of string or function
reference.
((jmespath "array_of(`1`, `2`, `3`)") 'null)=> '(1 2 3)
(import (rnrs) (text json mutable)) (define json '#(("key" . "value"))) (define mutable-json (json->mutable-json json)) (mutable-json-object-set! mutable-json "key" '#(("value" . "as object"))) (mutable-json->json mutable-json) ;; -> #(("key" . #(("value" . "as object"))))
#t
if the given obj is a mutable JSON,
otherwise #f
.#t
if the given obj is a mutable JSON object,
otherwise #f
.#t
if the given key exists in the
mutable-json-object, otherwise #f
.mutable JSON not found
object.
#t
if the given obj is a mutable JSON not found,
otherwise #f
.#t
if the given obj is a mutable JSON array
otherwise #f
.example.json
.
{ "id": 1234, "data": { "datum0": [0, 1, 2], "datum1": [3, 4] } }
(import (rnrs) (rfc json-pointer) (text json)) (define id-pointer (json-pointer "/id")) (let ((json (call-with-input-file "example.json" json-read))) (id-pointer json))=> 1234
(import (rnrs) (rfc json-pointer) (text json)) (define data-pointer (json-pointer "/data")) #| example.json |# (let ((json (call-with-input-file "example.json" json-read))) ;; Retrievs /data/datum0 ((json-pointer "/datum0" data-pointer) json))=> '(0 1 2)
/
.
The optional argument parent is passed, then it must be a procedure
returned by the json-pointer
and is called before the current
pointer is processed.
example.json
.
{ "id": 1234, "data": { "datum0": [0, 1, 2], "datum1": [3, 4] } }
(import (rnrs) (text json patch) (text json)) (define data-patcher (json-patcher '(#(("op" . "replace") ("path" . "/data/datum0") ("value" . "ok")) #(("op" . "remove") ("path" . "/data/datum1"))))) (let ((json (call-with-input-file "example.json" json-read))) (data-patcher json))=> #((id . 1234) (data . #((datum0 . ok))))
&json-patch
condition.
&json-patch
is the base condition of this library. The hierarchy is
the following:
&json-patch + &json-patch:runtime (path) + &json-patch-path-not-found + &json-patch-illegal-type + &json-patch:compile (patch)
&json-patch:compile
condition.&json-patch:runtime
condition.&json-patch-path-not-found
condition.&json-patch-illegal-type
condition.path
field of the given json-patch-error if
the condition is type of &json-patch-runtime
.patch
field of the given json-patch-error if
the condition is type of &json-patch-compile
.product.schema.json
{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "http://example.com/product.schema.json", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "productId": { "description": "The unique identifier for a product", "type": "integer" }, "productName": { "description": "Name of the product", "type": "string" }, "price": { "description": "The price of the product", "type": "number", "exclusiveMinimum": 0 } }, "required": [ "productId", "productName", "price" ] }We want to validate the following 2 JSON files whose content are the below:
valid-product.json
invalid-product.json
{ "productId": 1, "productName": "A green door", "price": 12.50, "tags": [ "home", "green" ] }
{ "productId": "This must be an integer", "productName": 1234, "price": -1 }For the simple validation, you can write the following code:
(import (rnrs) (text json) (text json schema) (text json validator)) (define product-catalogue-schema (json-schema->json-validator (call-with-input-file "product.schema.json" json-read))) (define valid-catalogue (call-with-input-file "valid-product.json" json-read)) (define invalid-catalogue (call-with-input-file "invalid-product.json" json-read)) (values (validate-json product-catalogue-schema valid-catalogue) (validate-json product-catalogue-schema invalid-catalogue))=> (values #t #f)
(import (rnrs) (text json) (text json schema) (text json validator) (srfi :39 parameters)) (define product-catalogue-schema (json-schema->json-validator (call-with-input-file "product.schema.json" json-read))) (define valid-catalogue (call-with-input-file "valid-product.json" json-read)) (define invalid-catalogue (call-with-input-file "invalid-product.json" json-read)) (parameterize ((*json-schema:validator-error-reporter* simple-json-schema-error-reporter)) (values (validate-json product-catalogue-schema valid-catalogue) (validate-json product-catalogue-schema invalid-catalogue))) ;; Prints the following #| /productId object: "This must be an integer" type: integer |#=> (values #t #f)
(import (rnrs) (text json) (text json schema) (text json validator) (srfi :39 parameters)) (define product-catalogue-schema (json-schema->json-validator (call-with-input-file "product.schema.json" json-read))) (define valid-catalogue (call-with-input-file "valid-product.json" json-read)) (define invalid-catalogue (call-with-input-file "invalid-product.json" json-read)) (parameterize ((*json-schema:validator-error-reporter* simple-json-schema-error-reporter) (*json-schema:lint-mode?* #t)) (values (validate-json product-catalogue-schema valid-catalogue) (validate-json product-catalogue-schema invalid-catalogue))) ;; Prints the following #| /productId object: "This must be an integer" type: integer /productName object: 1234 type: string /price object: -1 exclusive-minimum: 0 |#=> (values #t #t)
#t
.
"$ref": "http://json-schema.org/schema#"
.
The default value is #f
.
"format"
keywords.
The default value is #t
.
simple-json-schema-error-reporter
.
(current-error-port)
*json-schema:validator-error-reporter*
must also be specified.
The default value is #f
.
validator
field.
#t
if the given obj is a JSON validator,
otherwise #f
.validator
field value of the given
json-validator.
validator
field of given JSON validator with
parameter of json.
html->sxml-2nf
procedure normalizes attributes if it doesn't have
value. Others don't. Normalization in this context means adding attribute name
as its value.
current-output-port
is used.
Optional argument error-filter is used when unexpected SHTML entity is
met. It must be a procedure takes 2 arguments, unexpected entity and boolean
flag indicates if the entity is attribute or not. By default, it raises an
error.
*COMMENT*
, *DECL*
, *EMPTY*
,
*END*
, *ENTITY*
, *PI*
, *START*
, *TEXT*
and
*TOP*
respectively.
*ENTITY*
as public identifier.
(make-shtml-entity 151)=> (& 151)
sxml
markdown-sexp->sxml
to convert raw markdown S-expression.html
markdown-sexp->string
to convert raw markdown S-expression.sexp
parse-markdown
. The rest argument opt
is passed to both parse-markdown
and underlying convertion procedure.
So if you want to read a markdown document as an HTML string without
indentation, then the procedure should be called like the following:
(markdown-read in :as 'html :no-indent #t)
markdown-read
. It opens string
input port of string and call the markdown-read
.
The rest argument opt is passed to markdown-read
.
#
up to 6 of them is supported.
# header\n=> <h1>header</h1>
=
or -
in its
next line is supported. The =
or -
can be more than one.
header =======> <h1>header</h1>
>
is supported.
> sentence1 > sentence2=> <blockquote>sentence1\nsentence2</blockquote>
" "
(4 spaces or one tab) is supported.
this is the sentence=> <pre>thie\n is\n the sentence</pre>
"```\n"
and end with
"```\n"
is supported.
``` (define (print . args) (for-each display args) (newline)) ```=> <pre>(define (print . args)\n (for-each display args) (newline))</pre>
"[^$name]: "
is
supported. To refer this note, use "[^$name]"
. $name
can be alphanumeric.
[^1]: note1=> <div id="notes"><ol><li>note1</li></div>
Note to refer [^1].=> <p>Note to refer <sup><a href="#id">1</a></sup>.
title
attribute with the value of
note.
"[$name]: "
is
supported. To refer this note, use "[^$name]"
. $name
can be alphanumeric. To refer the reference, use "[label][ref]"
.
[Ref]: http://foo (title) or [Ref]: http://foo 'title' or [Ref]: http://foo "title"=> <div id="references"><div>[Ref]: http://foo 'title'</div></div>
[label][Ref]=> <a href="http://foo">label</a>
markdown-sexp->sxml
passing sexp and
opts then converts the returned value to HTML string.
The keyword argument no-indent controls if the returning string
has indentation or not. If the value is true value, then returning string
doesn't have indentation.
position
and expexted
slot of the given
markdown parser error condition, respectively.
(*namespace* ((ns uri) ...) spec ...)
(* spec ...)
(+ spec ...)
(/ spec ...)
(? spec ...)
(<!> tag builder)
spec spec* ...
(tag ctr)
(tag ctr next)
(?? pred)
*
means 0 or more.
The +
means 1 or more. And the ?
means 0 or 1.
The fifth form of spec means cyclic structure.
The sixth form of spec means set of spec spec ....
The following shows how to use this DSL macro
(define builder (sxml-object-builder (*namespace* ((ns "urn:foo"))) (ns:bar list (ns:buz list) (foo list))))The above definition can build an object from the following SXML
(*TOP* (urn:foo:bar (urn:foo:buz "buz") (foo "foo")))A generic SXML builder can be written like this:
(define-record-type xml-object (fields name attributes contents)) (define xml-object-builder (sxml-object-builder (<!> (?? values) make-xml-object)))
write-tree
method for tree] using an output
string port, and returns the result string.
(yaml-read (open-string-input-port " %YAML 1.2 --- foo: bar boo: - 1 - 2 - 3 - 4"))=> '(#((foo . bar) (boo 1 2 3 4)))
(current-output-port)
.
(yaml-write '(#(("foo" . "bar") ("boo" 1 2 3 4)))) ;; Prints the following #| %YAML 1.2 --- foo: bar boo: - 1 - 2 - 3 - 4 ... |#
(import (util timer)) (let ((timer (make-timer))) (timer-start! timer) ;; start timer ;; execute given thunk starting after 1000ms and each 1000ms (timer-schedule! timer (lambda () (display "timer!") (newline)) 1000 1000) ;; do something (timer-cancel! timer))A timer is kind of task queue running on a timer thread. Once it's started, then it waits until its queue is not empty or the first task reaches the configured time. The tasks are executed sequentially however its order is not reliable if there are multiple tasks queued on the same time.
created
state timer.
If the given timer's state is stopped
, then this procedure resumes
the given timer.
If the timer state is not created
or stopped
, then
&assertion
is raised.
timer-remove!
and timer-exists?
procedures.
timer-schedule!
.
object-builder
specifies how to construct a TLV
object. The default value is tlv-builder
.
()
.make-emv-tlv-parser
procedure.
fold
.
treemap-for-each
returns unspecified value. The
treemap-map
returns a list of the proc result.
These procedures are analogous to for-each
and map
respectively.
(srfi :43 vectors)
nor (srfi :133 vectors)
.
vector-filter
uses the elements which pred returns true value.
The vector-remove
removes the elements which pred returns
true value.
match
is originally from Alex Shin's `portable hygineic pattern matcher'
The documents below are derived from his source code.
syntax-rules
and thus preserving hygiene.
The most notable extensions are the ability to use non-linear
patterns - patterns in which the same identifier occurs multiple
times, tail patterns after ellipsis, and the experimental tree patterns.
(match expr (pat body ...) ...)where the result of expr is matched against each pattern in turn, and the corresponding body is evaluated for the first to succeed. Thus, a list of three elements matches a list of three elements.
(let ((ls (list 1 2 3))) (match ls ((1 2 3) #t)))If no patterns match an error is signalled. Identifiers will match anything, and make the corresponding binding available in the body.
(match (list 1 2 3) ((a b c) b))If the same identifier occurs multiple times, the first instance will match anything, but subsequent instances must match a value which is
equal?
to the first.
(match (list 1 2 1) ((a a b) 1) ((a b a) 2))The special identifier
_
matches anything, no matter how
many times it is used, and does not bind the result in the body.
(match (list 1 2 1) ((_ _ b) 1) ((a b a) 2))To match a literal identifier (or list or any other literal), use
quote
.
(match 'a ('b 1) ('a 2))Analogous to its normal usage in scheme,
quasiquote
can
be used to quote a mostly literally matching object with selected
parts unquoted.
(match (list 1 2 3) (`(1 ,b ,c) (list b c)))Often you want to match any number of a repeated pattern. Inside a list pattern you can append
...
after an element to
match zero or more of that pattern (like a regexp Kleene star).
(match (list 1 2) ((1 2 3 ...) #t))
(match (list 1 2 3) ((1 2 3 ...) #t))
(match (list 1 2 3 3 3) ((1 2 3 ...) #t))Pattern variables matched inside the repeated pattern are bound to a list of each matching instance in the body.
(match (list 1 2) ((a b c ...) c))
(match (list 1 2 3) ((a b c ...) c))
(match (list 1 2 3 4 5) ((a b c ...) c))More than one
...
may not be used in the same list, since
this would require exponential backtracking in the general case.
However, ...
need not be the final element in the list,
and may be succeeded by a fixed number of patterns.
(match (list 1 2 3 4) ((a b c ... d e) c))
(match (list 1 2 3 4 5) ((a b c ... d e) c))
(match (list 1 2 3 4 5 6 7) ((a b c ... d e) c))
___
is provided as an alias for ...
when it is
inconvenient to use the ellipsis (as in a syntax-rules
template).
The ..1
syntax is exactly like the ...
except
that it matches one or more repetitions (like a regexp "+").
(match (list 1 2) ((a b c ..1) c))
(match (list 1 2 3) ((a b c ..1) c))The boolean operators
and
, or
and not
can be used to group and negate patterns analogously to their
Scheme counterparts.
The and
operator ensures that all subpatterns match.
This operator is often used with the idiom (and x pat)
to
bind x to the entire value that matches pat
(c.f. "as-patterns" in ML or Haskell). Another common use is in
conjunction with not
patterns to match a general case
with certain exceptions.
(match 1 ((and) #t))
(match 1 ((and x) x))
(match 1 ((and x 1) x))The
or
operator ensures that at least one subpattern
matches. If the same identifier occurs in different subpatterns,
it is matched independently. All identifiers from all subpatterns
are bound if the or
operator matches, but the binding is
only defined for identifiers from the subpattern which matched.
(match 1 ((or) #t) (else #f))
(match 1 ((or x) x))
(match 1 ((or x 2) x))The
not
operator succeeds if the given pattern doesn't
match. None of the identifiers used are available in the body.
(match 1 ((not 2) #t))The more general operator
?
can be used to provide a
predicate. The usage is (? predicate pat ...)
where
predicate is a Scheme expression evaluating to a predicate
called on the value to match, and any optional patterns after the
predicate are then matched as in an and
pattern.
(match 1 ((? odd? x) x))The field operator
=
is used to extract an arbitrary
field and match against it. It is useful for more complex or
conditional destructuring that can't be more directly expressed in
the pattern syntax. The usage is (= field pat)
, where
field can be any expression, and should result in a
procedure of one argument, which is applied to the value to match
to generate a new value to match against pat.
Thus the pattern (and (= car x) (= cdr y))
is equivalent
to (x . y)
, except it will result in an immediate error
if the value isn't a pair.
(match '(1 . 2) ((= car x) x))
(match 4 ((= sqrt x) x))The record operator
$
is used as a concise way to match
records defined by SRFI-9 (or SRFI-99). The usage is
($ rtd field ...)
, where rtd should be the record
type descriptor specified as the first argument to
define-record-type
, and each field is a subpattern
matched against the fields of the record in order. Not all fields
must be present.
(let () (define-record-type employee (make-employee name title) employee? (name get-name) (title get-title)) (match (make-employee "Bob" "Doctor") (($ employee n t) (list t n))))The
set!
and get!
operators are used to bind an
identifier to the setter and getter of a field, respectively. The
setter is a procedure of one argument, which mutates the field to
that argument. The getter is a procedure of no arguments which
returns the current value of the field.
(let ((x (cons 1 2))) (match x ((1 . (set! s)) (s 3) x)))
(match '(1 . 2) ((1 . (get! g)) (g)))The new operator
***
can be used to search a tree for
subpatterns. A pattern of the form (x *** y)
represents
the subpattern y located somewhere in a tree where the path
from the current object to y can be seen as a list of the
form (x ...)
. y can immediately match the current
object in which case the path is the empty list. In a sense it's
a 2-dimensional version of the ...
pattern.
As a common case the pattern (_ *** y)
can be used to
search for y anywhere in a tree, regardless of the path
used.
(match '(a (a (a b))) ((x *** 'b) x))
(match '(a (b) (c (d e) (f g))) ((x *** 'g) x))
lambda
+ match
. Creates a
procedure of one argument, and matches that argument against each
clause.
match-lambda
. Creates a procedure of any
number of arguments, and matches the argument list against each
clause.
match-let
, but analogously to letrec
matches and binds the variables with all match variables in scope.
(text parse)
library is inspired and compatible with Oleg
Kiselyov's input parsing library. You can use this library in place of his
'input-parse.scm'
and 'look-for-str.scm'
.`?'
in its name, it may return
non-boolean value, contrary to the Scheme convention.
*eof*
.*eof*
is included, the EOF
condition is also included. Without *eof*
, the EOF condition is regarded
as an error.
*eof*
.
*eof*
is not included in
break-char-list, an error is signalled with comment is included in the
message.
get-string-n
.
(text sxml *)
libraries are the adaptation of Oleg Kiselyov's
SXML framework SSAX, which is based on S-expression representation of XML
structure.
SSAX is a parser part of SXML framework.
This is a quote from SSAX webpage:
The framework consists of a DOM/SXML parser, a SAX parser, and a supporting library of lexing and parsing procedures. The procedures in the package can be used separately to tokenize or parse various pieces of XML documents. The framework supports XML Namespaces, character, internal and external parsed entities, xml:space, attribute value normalization, processing instructions and CDATA sections. The package includes a semi-validating SXML parser: a DOM-mode parser that is an instantiation of a SAX parser (called SSAX). The parsing framework offers support for XML validation, to the full or any user-specified degree. Framework's procedures by themselves detect great many validation errors and almost all well-formedness errors. Furthermore, a user is given a chance to set his own handlers to capture the rest of the errors. Content is validated given user-specified constraints, which the user can derive from a DTD, from an XML schema, or from other competing doctype specification formats. SSAX is a full-featured, algorithmically optimal, pure-functional parser, which can act as a stream processor. SSAX is an efficient SAX parser that is easy to use. SSAX minimizes the amount of application-specific state that has to be shared among user-supplied event handlers. SSAX makes the maintenance of an application-specific element stack unnecessary, which eliminates several classes of common bugs. SSAX is written in a pure-functional subset of Scheme. Therefore, the event handlers are referentially transparent, which makes them easier for a programmer to write and to reason about. The more expressive, reliable and easier to use application interface for the event-driven XML parsing is the outcome of implementing the parsing engine as an enhanced tree fold combinator, which fully captures the control pattern of the depth-first tree traversal.Sagittarius supports the latest version of SSAX 5.1.
parser:: (Start-tag -> Seed -> Seed) -> (Start-tag -> Seed -> Seed -> Seed) -> (Char-Data -> Seed -> Seed) -> XML-text-fragment -> Seed -> Seed parser fdown fup fchar "<elem attrs> content </elem>" seed = fup "<elem attrs>" seed (parser fdown fup fchar "content" (fdown "<elem attrs>" seed)) parser fdown fup fchar "char-data content" seed = parser fdown fup fchar "content" (fchar "char-data" seed) parser fdown fup fchar "elem-content content" seed = parser fdown fup fchar "content" ( parser fdown fup fchar "elem-content" seed)Compare the last two equations with the left fold fold-left kons elem:list seed = fold-left kons list (kons elem seed) The real parser created my ssax:make-parser is slightly more complicated, to account for processing instructions, entity references, namespaces, processing of document type declaration, etc. The XML standard document referred to in this module is http://www.w3.org/TR/1998/REC-xml-19980210.html The present file also defines a procedure that parses the text of an XML document or of a separate element into SXML, an S-expression-based model of an XML Information Set. SXML is also an Abstract Syntax Tree of an XML document. SXML is similar but not identical to DOM; SXML is particularly suitable for Scheme-based XML/HTML authoring, SXPath queries, and tree transformations. See SXML.html for more details. SXML is a term implementation of evaluation of the XML document [3]. The other implementation is context-passing. The present frameworks fully supports the XML Namespaces Recommendation: http://www.w3.org/TR/REC-xml-names/ Other links: [1] Jeremy Gibbons, Geraint Jones, "The Under-appreciated Unfold," Proc. ICFP'98, 1998, pp. 273-279. [2] Richard S. Bird, The promotion and accumulation strategies in transformational programming, ACM Trans. Progr. Lang. Systems, 6(4):487-504, October 1984. [3] Ralf Hinze, "Deriving Backtracking Monad Transformers," Functional Pearl. Proc ICFP'00, pp. 186-197.
START
, END
, PI
, DECL
, COMMENT
,
CDSECT
or ENTITY-REF
that identifies a markup token
(named-entity-name . named-entity-body)where named-entity-name is a symbol under which the entity was declared, named-entity-body is either a string, or (for an external entity) a thunk that will return an input port (from which the entity can be read). named-entity-body may also be #f. This is an indication that a named-entity-name is currently being expanded. A reference to this named-entity-name will be an error: violation of the WFC nonrecursion.
<P> => kind='START, head='P </P> => kind='END, head='P <BR/> => kind='EMPTY-EL, head='BR <!DOCTYPE OMF ...> => kind='DECL, head='DOCTYPE <?xml version="1.0"?> => kind='PI, head='xml &my-ent; => kind = 'ENTITY-REF, head='my-entCharacter references are not represented by xml-tokens as these references are transparently resolved into the corresponding characters.
(elem-name elem-content decl-attrs)elem-name is an UNRES-NAME for the element. elem-content is an ELEM-CONTENT-MODEL. decl-attrs is an ATTLIST, of (ATTR-NAME . VALUE) associations !!!This element can declare a user procedure to handle parsing of an element (e.g., to do a custom validation, or to build a hash of IDs as they're encountered).
(attr-name content-type use-type default-value)attr-name is an UNRES-NAME for the declared attribute content-type is a symbol: CDATA, NMTOKEN, NMTOKENS, ... or a list of strings for the enumerated type. use-type is a symbol: REQUIRED, IMPLIED, FIXED default-value is a string for the default value, or #f if not given.
[3] S ::= (#x20 | #x9 | #xD | #xA)The procedure returns the first not-whitespace character it encounters while scanning the port. This character is left on the input stream.
[4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender [5] Name ::= (Letter | '_' | ':') (NameChar)*This code supports the XML Namespace Recommendation REC-xml-names, which modifies the above productions as follows:
[4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender [5] NCName ::= (Letter | '_') (NCNameChar)*As the Rec-xml-names says, "An XML document conforms to this specification if all other tokens [other than element types and attribute names] in the document which are required, for XML conformance, to match the XML production for Name, match this specification's production for NCName." Element types and attribute names must match the production QName, defined below.
From REC-xml-names: [6] QName ::= (Prefix ':')? LocalPart [7] Prefix ::= NCName [8] LocalPart ::= NCNameReturn: an UNRES-NAME
[16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
ssax:read-cdata-body
as the third argument. The result of this first invocation will be
passed as the seed argument to the second invocation of the line
consumer, and so on. The result of the last invocation of the
STR-HANDLER is returned by the ssax:read-cdata-body. Note a
similarity to the fundamental 'fold' iterator.
Within a CDATA section all characters are taken at their face value,
with only three exceptions:
[66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'This procedure must be called after we we have read "&#" that introduces a char reference. The procedure reads this reference and returns the corresponding char The current position in port will be after ";" that terminates the char reference Faults detected:
"[Definition: A character reference refers to a specific character in the ISO/IEC 10646 character set, for example one not directly accessible from available input devices.]"Therefore, we use a ucscode->char function to convert a character code into the character -- *regardless* of the current character encoding of the input stream.
[41] Attribute ::= Name Eq AttValue [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" [25] Eq ::= S? '=' S?The procedure returns an ATTLIST, of Name (as UNRES-NAME), Value (as string) pairs. The current character on the PORT is a non-whitespace character that is not an ncname-starting character. Note the following rules to keep in mind when reading an 'AttValue' "Before the value of an attribute is passed to the application or checked for validity, the XML processor must normalize it as follows:
[75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]This procedure is supposed to be called when an ExternalID is expected; that is, the current character must be either #\S or #\P that start correspondingly a SYSTEM or PUBLIC token. This procedure returns the SystemLiteral as a string. A PubidLiteral is disregarded if present.
[1] document ::= prolog element Misc* [22] prolog ::= XMLDecl? Misc* (doctypedec l Misc*)? [27] Misc ::= Comment | PI | SThe following function should be called in the prolog or epilog contexts. In these contexts, whitespaces are completely ignored. The return value from ssax:scan-Misc is either a PI-token, a DECL-token, a START token, or EOF. Comments are ignored and not reported.
[43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*To be more precise, the procedure reads CharData, expands CDSect and character entities, and skips comments. The procedure stops at a named reference, EOF, at the beginning of a PI or a start/end tag.
ssax:make-pi-parser
is a
procedure PORT PI-TAG SEEDthat will parse the current PI according to the user-specified handlers.
procedure START-TAG-HEAD PORT ELEMS ENTITIES NAMESPACES PRESERVE-WS? SEEDThe procedure must be called after the start tag token has been read. START-TAG-HEAD is an UNRES-NAME from the start-element tag. ELEMS is an instance of xml-decl::elems. See
ssax:complete-start-tag::preserve-ws?
Faults detected:
ssax:make-elem-parser
, my-new-level-seed
ssax:make-elem-parser
, my-finish-element
ssax:make-elem-parser
, my-char-data-handler
ssax:make-pi-parser
The default value is '()
The generated parser is a
procedure PORT SEED
This procedure parses the document prolog and then exits to
an element parser (created by ssax:make-elem-parser
) to handle
the rest.
[1] document ::= prolog element Misc* [22] prolog ::= XMLDecl? Misc* (doctypedec | Misc*)? [27] Misc ::= Comment | PI | S [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' (markupdecl | PEReference | S)* ']' S?)? '>' [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment
ssax:reverse-collect-str
procedure instead.
http://www.w3.org/TR/xpathXPath and SXPath describe means of selecting a set of Infoset's items or their properties. To facilitate queries, XPath maps the XML Infoset into an explicit tree, and introduces important notions of a location path and a current, context node. A location path denotes a selection of a set of nodes relative to a context node. Any XPath tree has a distinguished, root node -- which serves as the context node for absolute location paths. Location path is recursively defined as a location step joined with a location path. A location step is a simple query of the database relative to a context node. A step may include expressions that further filter the selected set. Each node in the resulting set is used as a context node for the adjoining location path. The result of the step is a union of the sets returned by the latter location paths. The SXML representation of the XML Infoset (see SSAX.scm) is rather suitable for querying as it is. Bowing to the XPath specification, we will refer to SXML information items as 'Nodes':
<Node> ::= <Element> | <attributes-coll> | <attrib> | "text string" | <PI>This production can also be described as
<Node> ::= (name . <Nodelist>) | "text string"An (ordered) set of nodes is just a list of the constituent nodes:
<Nodelist> ::= (<Node> ...)Nodelists, and Nodes other than text strings are both lists. A <Nodelist> however is either an empty list, or a list whose head is not a symbol. A symbol at the head of a node is either an XML name (in which case it's a tag of an XML element), or an administrative name such as '@'. This uniform list representation makes processing rather simple and elegant, while avoiding confusion. The multi-branch tree structure formed by the mutually-recursive datatypes <Node> and <Nodelist> lends itself well to processing by functional languages. A location path is in fact a composite query over an XPath tree or its branch. A singe step is a combination of a projection, selection or a transitive closure. Multiple steps are combined via join and union operations. This insight allows us to _elegantly_ implement XPath as a sequence of projection and filtering primitives -- converters -- joined by _combinators_. Each converter takes a node and returns a nodelist which is the result of the corresponding query relative to that node. A converter can also be called on a set of nodes. In that case it returns a union of the corresponding queries over each node in the set. The union is easily implemented as a list append operation as all nodes in a SXML tree are considered distinct, by XPath conventions. We also preserve the order of the members in the union. Query combinators are high-order functions: they take converter(s) (which is a Node|Nodelist -> Nodelist function) and compose or otherwise combine them. We will be concerned with only relative location paths [XPath]: an absolute location path is a relative path applied to the root node. Similarly to XPath, SXPath defines full and abbreviated notations for location paths. In both cases, the abbreviated notation can be mechanically expanded into the full form by simple rewriting rules. In case of SXPath the corresponding rules are given as comments to a sxpath function, below. The regression test suite at the end of this file shows a representative sample of SXPaths in both notations, juxtaposed with the corresponding XPath expressions. Most of the samples are borrowed literally from the XPath specification, while the others are adjusted for our running example, tree1.
type Converter = Node|Nodelist -> NodelistA converter can also play a role of a predicate: in that case, if a converter, applied to a node or a nodelist, yields a non-empty nodelist, the converter-predicate is deemed satisfied. Throughout this file a nil nodelist is equivalent to #f in denoting a failure.
ntype-names?? :: ListOfNames -> Node -> Boolean
ntype?? :: Crit -> Node -> BooleanThe criterion 'crit' is one of the following symbols:
(ntype-namespace-id?? #f)
will be #t for nodes with non-qualified names.
((apply node-reduce converters) nodelist)is equivalent to
(foldl apply nodelist converters)i.e., folding, or reducing, a list of converters with the nodelist as a seed.
(define (node-closure f) (node-or (select-kids f) (node-reduce (select-kids (ntype?? '*)) (node-closure f))))This definition, as written, looks somewhat like a fixpoint, and it will run forever. It is obvious however that sooner or later (select-kids (ntype?? '*)) will return an empty nodelist. At this point further iterations will no longer affect the result and can be stopped.
((sxml:parent test-pred) rootnode)and returns a parent of a node it is applied to. If applied to a nodelist, it returns the list of parents of nodes in the nodelist. The rootnode does not have to be the root node of the whole SXML tree -- it may be a root node of a branch of interest. The parent:: axis can be used with any SXML node.
(sxml:child sxml:node?)
(select-kids sxml:element)
sxpath:: AbbrPath -> Converter, or sxpath:: AbbrPath -> Node|Nodeset -> NodesetAbbrPath is a list. It is translated to the full SXPath according to the following rewriting rules
(sxpath '()) -> (node-join) (sxpath '(path-component ...)) -> (node-join (sxpath1 path-component) (sxpath '(...))) (sxpath1 '//) -> (sxml:descendant-or-self sxml:node?) (sxpath1 '(equal? x)) -> (select-kids (node-equal? x)) (sxpath1 '(eq? x)) -> (select-kids (node-eq? x)) (sxpath1 '(*or* ...)) -> (select-kids (ntype-names?? (cdr '(*or* ...)))) (sxpath1 '(*not* ...)) -> (select-kids (sxml:complement (ntype-names?? (cdr '(*not* ...))))) (sxpath1 '(ns-id:* x)) -> (select-kids (ntype-namespace-id?? x)) (sxpath1 ?symbol) -> (select-kids (ntype?? ?symbol)) (sxpath1 ?string) -> (txpath ?string) (sxpath1 procedure) -> procedure (sxpath1 '(?symbol ...)) -> (sxpath1 '((?symbol) ...)) (sxpath1 '(path reducer ...)) -> (node-reduce (sxpath path) (sxpathr reducer) ...) (sxpathr number) -> (node-pos number) (sxpathr path-filter) -> (filter (sxpath path-filter))
NOTE: 1. When converting a nodeset - a document order is not preserved 2. number->string function returns the result in a form which is slightlydifferent from XPath Rec. specification
NOTE: 1. The argument is not optional (yet?) 2. string->number conversion is not IEEE 754 round-to-nearest 3. NaN is represented as 0
object - a nodeset or a datatype which can be converted to a string by meansof a 'string' function
id-index = ( (id-value . element) (id-value . element) ... )This index is used for selection of an element by its unique ID. The result is a nodeset
(sxml:equality-cmp (lambda (bool1 bool2) (not (eq? bool1 bool2))) (lambda (num1 num2) (not (= num1 num2))) (lambda (str1 str2) (not (string=? str1 str2))))Counterparts of
sxml:equal?
.
packrat-parse
macro and the combinators into into which it expands, the
base-generator->results
function, and the accessors for
parse-result
records.
parse-result-next
had completed successfully, consuming the [a, b, c] prefix of the input stream
and producing some semantic value, then the parse-result returned from
parse-result-next
would represent all possible parses starting from the
[d, e] suffix of the input stream.base
and code{next}
represent the implicit successful parse of a base value at the current position.
The base
field contains a pair of a toke-class-identifier and a semantic
value unless the parse-results data structure as a whole is representing the of
the input stream, in which case it will contain #f.
parse-results-base
, if that result is a pair; otherwise it returns
#f.parse-results-base
, if that result is a pair; otherwise it returns
#f.parse-results-base
, if that result is a pair; otherwise it returns #f.r
is a parse-results representing parse over the input
token stream '((b . 2) (c . 3))
, then the result of the call
(prepend-base #f '(a . 1) r)is a new parse-results representing parse over the input stream
'((a . 1) (b . 2) (c . 3))
.
The first argument to prepend-base, the parse-position, should be either a
parse-position representing the location the base token being prepended, or #f
if the input position of the base token is unknown.results->result
.make-expected-result
.make-message-result
.merge-result-errors
.make-parse-position
as the "filename"
parameter, and so may be either a string or #f.#\return
, which
resets the column number to zero; #\newline
, which both resets the column
number to zero and increments the line number; and #\tab
, which
increments the column number to the nearest multiple of eight, just as terminal
with an eight-column tab stop setting might do.filename:linenumber:columnnumberfor example,
main.c:33:7
parse-results -> parse-result
semanticValue -> parserCombinatoror more fully expanded,
semanticValue -> parse-results -> parse-resultThese types recall the types of functions that work with monads.
packrat-check-base
) and continues parsing using the resulting
combinator.packrat-parse
macro provides syntactic sugar for building complex
parser combinators from simpler combinators. The general form of the macro, in
an EBNF-like language, is:
(packrat-parser <result-expr> <nonterminal-definition>*)where
<nonterminal-definition> :== (<nonterminal-id> (<sequence> <body-expr>+)*) <sequence> :== (<part>*) <part> :== (! <part>*) | (/ <sequence>*) | <var> <- '<kind-object> | <var> <- | <var> <- <nonterminal-id> | '<kind-object> | <nonterminal-id>Each nonterminal-definition expands into a parser-combinator. The collection of defined nonterminal parser-combinators expands to a
(begin)
containing an
internal definition for each nonterminal.
The result of the whole packrat-parser
form is the <result-expr>
immediately following the packrat-parser
keyword. Since (begin)
within (begin)
forms are flattened out in Scheme, the
<result-expr>
can be used to introduce handwritten parser combinators
which can call, and can be called by, the nonterminal definitions built in the
rest of the parser definition.
Each nonterminal definition expands into:
(define (<nonterminal-id> results) (results->result results 'nonterminal-id (lambda () (<...> results))))where
<...>
is the expanded definition-of-sequences combinator formed
form the body of the nonterminal definition.
An alternation (either implicit in the main body of a nonterminal definition, or
introduced via a <part>
of the form (/ <sequence> ...)
)
expands to
(packrat-or <expansion-of-first-alternative>
(packrat-or <expansion-of-second-alternative>
...))
This causes each alternative to be tried in turn, in left-to-right order of
occurrence.
Wherever a <part>
of the form "<var> <- ..."
occurs, a
variable binding for <var>
is made available in the <body-expr>
s
that make up each arm of a nonterminal definition. The variable will be bound to
the semantic value resulting form parsing according to the parser definition to
the right of the arrow (the "..."
above).
The (! <part> ...)
syntax expands into an invocation of
packrat-unless
.
The "@"
syntax in "<var> <- @"
causes <var>
to be bound to the parse-position at that point in the input stream. This can be
used for annotating abstract syntax trees with location information.
<part>
s of the form '<kind-object>
expand into invocations of
packrat-check-base
; those of the form <nonterminal-id>
expand
into invocations of packrat-check
, with the procedure associated with
the named nonterminal passed in as the combinator argument.
JSON array <-> list
JSON table <-> vector
JSON boolean <-> boolean
JSON null <-> symbol null
Read and write procedure always use above conversion rules even if
*json-map-type*
is set to 'alist
.
SRFI number | Library name |
---|---|
SRFI-0 | (srfi :0 cond-expand) |
SRFI-1 | (srfi :1 lists) |
SRFI-2 | (srfi :2 and-let*) |
SRFI-4 | (srfi :4 numeric-vectors) This SRFI also contains reader macro described below this section. |
SRFI-6 | (srfi :6 basic-string-ports) |
SRFI-8 | (srfi :8 receive) |
SRFI-11 | (srfi :11 let-values) |
SRFI-13 | (srfi :13 strings) |
SRFI-14 | (srfi :14 char-set) |
SRFI-16 | (srfi :16 case-lambda) |
SRFI-17 | (srfi :17 generalized-set!) |
SRFI-18 | (srfi :18 multithreading) |
SRFI-19 | (srfi :19 time) |
SRFI-22 | This SRFI does not provide any library. |
SRFI-23 | (srfi :23 error) |
SRFI-25 | (srfi :25 multi-dimensional-arrays) |
SRFI-26 | (srfi :26 cut) |
SRFI-27 | (srfi :27 random-bits) |
SRFI-29 | (srfi :27 localization) |
SRFI-31 | (srfi :31 rec) |
SRFI-37 | (srfi :37 args-fold) |
SRFI-38 | (srfi :38 with-shared-structure) |
SRFI-39 | (srfi :39 parameters) |
SRFI-41 | (srfi :41 streams) |
SRFI-42 | (srfi :42 eager-comprehensions) |
SRFI-43 | (srfi :43 vectors) |
SRFI-45 | (srfi :45 lazy) |
SRFI-49 | (srfi :49)
The library exports srfi-49-read , srfi-49-load procedures.
And also be able to replace reader, For more detail, see
(sagittarius reader) - reader macro library. |
SRFI-57 | (srfi :57 records) |
SRFI-60 | (srfi :60 integer-bits) |
SRFI-61 | This SRFI is supported by builtin cond |
SRFI-64 | (srfi :64 testing) |
SRFI-69 | (srfi :69 basic-hash-tables) |
SRFI-78 | (srfi :78 lightweight-testing) |
SRFI-86 | (srfi :86 mu-and-nu) |
SRFI-87 | (srfi :87 case) |
SRFI-98 | (srfi :98 os-environment-variables) |
SRFI-99 | (srfi :99 records) |
SRFI-100 | (srfi :100 define-lambda-object)
The long name is Sagittarius specific and the specified library name
is (srfi :100) . So for the portability it's better to use the
(srfi :100) .
The name define-lambda-object is taken from the SRFI name. |
SRFI-101 | (srfi :101 random-access-lists)
The long name is Sagittarius specific and the specified library name
is (srfi :101) . So for the portability it's better to use the
(srfi :101) .
The name random-access-lists is taken from the sample
implementation. |
SRFI-105 | (srfi :105)
The library exports curly-infix-read and neoteric-read
procedures. These procedures read SRFI-105 the infix style code that
SRFI-105 specifying. And this also exports reader macros, you can
activate it with #!read-macro=srfi/:105 or
#!read-macro=curly-infix .
Even though the specification said it MUST support #!curly-infix ,
however the library just ignore and not activate the reader macros. So
you need to explicitly write the one mentioned above. To keep your code
portable between implementations that support this SRFI, you need to write
both style as following;
;; write both #!read-macro=curly-infix #!curly-infixThe order doesn't matter, Sagittarius just ignores the latter style. |
SRFI-106 | (srfi :106 socket) |
SRFI-110 | (srfi :110)
The library exports a replacible reader. To use it write following
hash-bang directives.
;; write both for compatibility #!reader=sweet #!sweetThe order doesn't matter, Sagittarius just ignores the latter style. |
SRFI-111 | (srfi :111 boxes)
The long name is Sagittarius specific and the specified library name
is (srfi :111) . So for the portability it's better to use the
(srfi :111) .
The name boxes is taken from R7RS-large library name.
|
SRFI-112 | (srfi :112 inquery)
The long name is Sagittarius specific and the specified library name
is (srfi :112) . So for the portability it's better to use the
(srfi :112) .
The name inquery is taken from R7RS-large library name.
|
SRFI-113 | (srfi :113 sets)
The long name is Sagittarius specific and the specified library name
is (srfi :113) . So for the portability it's better to use the
(srfi :113) .
The name sets is taken from its name.
|
SRFI-114 | (srfi :114 comparators)
The long name is Sagittarius specific and the specified library name
is (srfi :114) . So for the portability it's better to use the
(srfi :114) .
The name comparators is taken from its name.
|
SRFI-115 | (srfi :115 regex) |
SRFI-116 | (srfi :116 ilists)
The long name is Sagittarius specific and the specified library name
is (srfi :116) . So for the portability it's better to use the
(srfi :116) .
The name ilists is taken from sample implementation.
|
SRFI-117 | (srfi :117 list-queues) |
SRFI-120 | (srfi :120 timer)
The long name is Sagittarius specific and the specified library name
is (srfi :120) . So for the portability it's better to use the
(srfi :120) .
The name timer is taken from sample implementation.
|
SRFI-121 | (srfi :121 generators)
The long name is Sagittarius specific and the specified library name
is (srfi :121) . So for the portability it's better to use the
(srfi :121) .
The name generators is taken from sample implementation.
|
SRFI-123 | (srfi :123 generic-ref)
The long name is Sagittarius specific and the specified library name
is (srfi :123) . So for the portability it's better to use the
(srfi :123) .
The name generic-ref is taken from the SRFI discussion.
Re: SRFI-97 name
|
SRFI-124 | (srfi :124 ephemerons)
The long name is Sagittarius specific and the specified library name
is (srfi :124) . So for the portability it's better to use the
(srfi :124) .
The name ephemerons is taken from the example implementation.
Current implementation of ephemerons has the same issue as the one
Chibi has. It is described in the SRFI document.
|
SRFI-125 | (srfi :125 hashtables) |
SRFI-126 | (srfi :126 r6rs-hashtables) |
SRFI-127 | (srfi :127 lazy-sequences) |
SRFI-128 | (srfi :128 comparators) |
SRFI-129 | (srfi :129 titlecase) |
SRFI-130 | (srfi :130 string-cursors) |
SRFI-131 | (srfi :131 records) |
SRFI-132 | (srfi :132 sorting) |
SRFI-133 | (srfi :133 vectors) |
SRFI-134 | (srfi :134 ideque)
The long name is Sagittarius specific and the specified library name
is (srfi :134) . So for the portability it's better to use the
(srfi :134) .
The name ideque is taken from sample implementation.
|
SRFI-135 | (srfi :135 texts)
The long name is Sagittarius specific and the specified library name
is (srfi :134) . So for the portability it's better to use the
(srfi :134) .
The name texts is taken from sample implementation.
|
SRFI-139 | (srfi :139 syntax-parameters)
The long name is Sagittarius specific and the specified library name
is (srfi :139) . So for the portability it's better to use the
(srfi :139) .
The name syntax-parameters is taken from sample implementation.
|
SRFI-141 | (srfi :141 integer-division) |
SRFI-142 | (srfi :142 bitwise)
The long name is Sagittarius specific and the specified library name
is (srfi :142) . So for the portability it's better to use the
(srfi :142) .
The name bitwise is taken from the name of the SRFI.
This SRFI is deprecated by SRFI-151.
|
SRFI-143 | (srfi :143 fixnums) |
SRFI-144 | (srfi :144 flonums)
The long name is Sagittarius specific and the specified library name
is (srfi :144) . So for the portability it's better to use the
(srfi :144) .
The name flonums is taken from the name of the SRFI.
|
SRFI-145 | (srfi :145 assumptions) |
SRFI-146 | (srfi :146 mapping) and (srfi :146 hash)
The long name is Sagittarius specific and the specified library name
is (srfi :146) and (srfi :146 hash) . So for the portability it's better to use them.
The name mapping is taken from the name of the SRFI.
|
SRFI-151 | (srfi :151 bitwise-operations) |
SRFI-152 | (srfi :152 strings)
This library doesn't extend comparisons, thus it behaves as the SRFI specifies.
(e.g. Passing 0 or 1 argument to string=? raises an error)
|
SRFI-156 | (srfi :156 predicate-combiners) |
SRFI-158 | (srfi :158 generators-and-accumulators) |
SRFI-159 | (srfi :159) |
SRFI-160 | (srfi :160)
The short name is Sagittarius specific which provides all the bindings
from the below libraries which are specified in the SRFI:
|
#/-reader | 6.11.1 User level APIs for regular expression |
#?= | 6.15 (sagittarius debug) - Debugging support |
/ | 3.3.14 Arithmetic operations |
/ | 3.3.14 Arithmetic operations |
/. | 6.1.3 Arithmetic operations |
/. | 6.1.3 Arithmetic operations |
? | 7.56.1 JSON object builder |
? | 7.56.2 JSON object serializer |
? | 7.66.1 High level APIs |
?? | 7.66.1 High level APIs |
^ | 6.2 (sagittarius control) - control library |
^c | 6.2 (sagittarius control) - control library |
^c* | 6.2 (sagittarius control) - control library |
yaml-read | 7.68 (text yaml) -- YAML parser |
yaml-write | 7.68 (text yaml) -- YAML parser |
yaml-write | 7.68 (text yaml) -- YAML parser |
Yarrow | 7.19.1 Random number operations |