doc work, especially I/O reference

svn: r6803
This commit is contained in:
Matthew Flatt 2007-07-03 03:32:13 +00:00
parent fe4857ee3c
commit 987982cd8d
22 changed files with 1996 additions and 998 deletions

View File

@ -180,7 +180,7 @@
;; ----------------------------------------
(provide defproc defproc* defstruct defthing defparam
(provide defproc defproc* defstruct defthing defparam defboolparam
defform defform* defform/subs defform*/subs defform/none
specform specform/subs
specsubform specsubform/subs specspecsubform specspecsubform/subs specsubform/inline
@ -242,11 +242,19 @@
(define-syntax defstruct
(syntax-rules ()
[(_ name fields #:immutable #:inspector #f desc ...)
(*defstruct (quote-syntax name) 'name 'fields #t #t (lambda () (list desc ...)))]
(**defstruct name fields #t #t desc ...)]
[(_ name fields #:immutable desc ...)
(*defstruct (quote-syntax name) 'name 'fields #t #f (lambda () (list desc ...)))]
(**defstruct name fields #t #f desc ...)]
[(_ name fields #:inspector #f desc ...)
(**defstruct name fields #f #t desc ...)]
[(_ name fields desc ...)
(*defstruct (quote-syntax name) 'name 'fields #f #f (lambda () (list desc ...)))]))
(**defstruct name fields #f #f desc ...)]))
(define-syntax **defstruct
(syntax-rules ()
[(_ name ([field field-contract] ...) immutable? transparent? desc ...)
(*defstruct (quote-syntax name) 'name
'([field field-contract] ...) (list (lambda () (schemeblock0 field-contract)) ...)
#t #t (lambda () (list desc ...)))]))
(define-syntax (defform*/subs stx)
(syntax-case stx ()
[(_ #:literals (lit ...) [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)
@ -351,6 +359,10 @@
(syntax-rules ()
[(_ id arg contract desc ...)
(defproc* ([(id) contract] [(id [arg contract]) void?]) desc ...)]))
(define-syntax defboolparam
(syntax-rules ()
[(_ id arg desc ...)
(defproc* ([(id) boolean?] [(id [arg any/c]) void?]) desc ...)]))
(define-syntax schemegrammar
(syntax-rules ()
[(_ #:literals (lit ...) id clause ...) (*schemegrammar '(lit ...)
@ -640,8 +652,9 @@
(map symbol->string (car wrappers)))))))
(cdr wrappers))))
(define (*defstruct stx-id name fields immutable? transparent? content-thunk)
(define (*defstruct stx-id name fields field-contracts immutable? transparent? content-thunk)
(define spacer (hspace 1))
(define to-flow (lambda (e) (make-flow (list (make-paragraph (list e))))))
(make-splice
(cons
(make-table
@ -649,48 +662,144 @@
(cons
(list (make-flow
(list
(make-paragraph
(list
(to-element
`(,(schemeparenfont "struct")
,(make-target-element*
stx-id
(to-element name)
(let ([name (if (pair? name)
(car name)
name)])
(list* (list name)
(list name '?)
(list 'make- name)
(append
(map (lambda (f)
(list name '- (car f)))
fields)
(if immutable?
null
(map (lambda (f)
(list 'set- name '- (car f) '!))
fields))))))
,(map car fields)
,@(if immutable? '(#:immutable) null)
,@(if transparent? '(#:inspector #f) null))))))))
(map (lambda (v)
(let* ([the-name
(make-target-element*
stx-id
(to-element (if (pair? name)
(map (lambda (x)
(make-just-context x stx-id))
name)
stx-id))
(let ([name (if (pair? name)
(car name)
name)])
(list* (list name)
(list name '?)
(list 'make- name)
(append
(map (lambda (f)
(list name '- (car f)))
fields)
(if immutable?
null
(map (lambda (f)
(list 'set- name '- (car f) '!))
fields))))))]
[short-width (apply +
(length fields)
8
(map (lambda (s)
(string-length (symbol->string s)))
(append (if (pair? name)
name
(list name))
(map car fields))))])
(if (and (short-width . < . max-proto-width)
(not immutable?)
(not transparent?))
(make-paragraph
(list
(to-element
`(,(schemeparenfont "struct")
,the-name
,(map car fields)))))
(make-table
#f
(append
(list
(list (to-flow (schemeparenfont "(struct"))
(to-flow spacer)
(to-flow the-name)
(if (or (null? fields)
(short-width . < . max-proto-width))
(to-flow spacer)
(to-flow (make-element #f
(list spacer
(schemeparenfont "(")))))
(to-flow (if (or (null? fields)
(short-width . < . max-proto-width))
(to-element (map car fields))
(to-element (caar fields))))))
(if (short-width . < . max-proto-width)
null
(let loop ([fields fields])
(if (null? fields)
null
(cons (let ([fld (car fields)])
(list (to-flow spacer)
(to-flow spacer)
(to-flow spacer)
(to-flow spacer)
(to-flow
(let ([e (to-element (car fld))])
(if (null? (cdr fields))
(make-element
#f
(list e
(schemeparenfont
(if (and (not immutable?)
(not transparent?))
"))"
")"))))
e)))))
(loop (cdr fields))))))
(cond
[(and immutable? transparent?)
(list
(list (to-flow spacer)
(to-flow spacer)
(to-flow (to-element '#:immutable))
'cont
'cont)
(list (to-flow spacer)
(to-flow spacer)
(to-flow (make-element
#f
(list (to-element '#:inspector)
spacer
(to-element #f)
(schemeparenfont ")"))))
'cont
'cont))]
[immutable?
(list
(list (to-flow spacer)
(to-flow spacer)
(to-flow (make-element
#f
(list (to-element '#:immutable)
(schemeparenfont ")"))))
'cont
'cont))]
[transparent?
(list
(list (to-flow spacer)
(to-flow spacer)
(to-flow (make-element
#f
(list (to-element '#:inspector)
spacer
(to-element #f)
(schemeparenfont ")"))))
'cont
'cont))]
[else null]))))))))
(map (lambda (v field-contract)
(cond
[(pair? v)
(list
(make-flow
(list
(make-paragraph (append
(list
(hspace 2)
(to-element (car v)))
(list
spacer
":"
spacer
(to-element (cadr v))))))))]
(make-table-if-necessary
#f
(list
(list (to-flow (hspace 2))
(to-flow (to-element (car v)))
(to-flow spacer)
(to-flow ":")
(to-flow spacer)
(make-flow (list (field-contract))))))))]
[else null]))
fields)))
fields field-contracts)))
(content-thunk))))
(define (*defthing stx-id name result-contract content-thunk)

View File

@ -53,7 +53,7 @@ side-effects based on a @scheme[_test-expr], use @scheme[when] or
@;------------------------------------------------------------------------
@section[#:tag "guide:and+or"]{Combining Tests: @scheme[and] and @scheme[or]}
@refalso["mz:and+or"]{@scheme[and] and @scheme[or]}
@refalso["mz:if"]{@scheme[and] and @scheme[or]}
Scheme's @scheme[and] and @scheme[or] are syntactic forms, rather than
functions. Unlike a function, the @scheme[and] and @scheme[or] forms
@ -99,7 +99,7 @@ The @scheme[cond] form chains a series of tests to select a result
expression. To a first approximation, the syntax of @scheme[cond] is
as follows:
@refalso["mz:cond"]{@scheme[cond]}
@refalso["mz:if"]{@scheme[cond]}
@specform[(cond [test-expr expr ...+]
...)]

View File

@ -19,7 +19,7 @@
(italic (link "../quick/index.html" "An Introduction to PLT Scheme with Pictures")))
(define MzScheme
(italic (link "../reference/index.html" "PLT Scheme Reference Manual")))
(italic (link "../reference/index.html" "PLT Scheme Reference")))
(define HtDP
(italic (link "http://www.htdp.org" "How to Design Programs")))

View File

@ -12,7 +12,7 @@ general information about continuation marks.
The list of continuation marks for a key @scheme[_k] and a continuation
@scheme[_C] that extends @cont[0] is defined as follows:
%
@itemize{
@item{If @scheme[_C] is an empty continuation, then the mark list is

View File

@ -951,7 +951,7 @@ procedures.
(write-special 'hello /dev/null-out)
(sync (write-bytes-avail-evt #"hello" /dev/null-out))
;; A part that accumulates bytes as characters in a list,
;; A port that accumulates bytes as characters in a list,
;; but not in a thread-safe way:
(define accum-list null)
(define accumulator/not-thread-safe

View File

@ -1,7 +1,7 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:style 'toc]{Core Datatypes and Procedures}
@title[#:style 'toc]{Core Datatypes}
Each of the built-in datatypes comes with a set of procedures for
manipulating members of the datatype.
@ -90,6 +90,9 @@ ephemeron key (see @secref["mz:ephemerons"]).
@examples[(gensym "apple")]
@; ------------------------------------------------------------
@include-section["regexps.scrbl"]
@; ------------------------------------------------------------
@section[#:tag "keywords"]{Keywords}

View File

@ -1,7 +1,7 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "mz:define-struct"]{Structure Types: @scheme[define-struct]}
@title[#:tag "mz:define-struct"]{Defining Structure Types: @scheme[define-struct]}
@guideintro["guide:define-struct"]{@scheme[define-struct]}
@ -22,8 +22,6 @@
[field-option #:immutable
#:auto])]{
@moreref["mz:structures"]{structures}
Creates a new @techlink{structure type}, and binds transformers and
variables related to the new @tech{structure type}. A
@scheme[define-struct] form with @math{n} @scheme[field]s defines

View File

@ -1,156 +0,0 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "mz:derived-syntax" #:style 'toc]{Derived Syntactic Forms}
@local-table-of-contents[]
@;------------------------------------------------------------------------
@section[#:tag "mz:cond"]{Conditionals: @scheme[cond]}
@guideintro["guide:cond"]{@scheme[cond]}
@defform/subs[#:literals (else =>)
(cond cond-clause ...)
([cond-clause [test-expr then-expr ...+]
[else then-expr ...+]
[test-expr => proc-expr]
[test-expr]])]{
A @scheme[cond-clause] that starts with @scheme[else] must be the last
@scheme[cond-clause].
If no @scheme[cond-clause]s are present, the result is @|void-const|.
If only a @scheme[[else then-expr ...+]] is present, then the
@scheme[then-expr]s are evaluated. The results from all but the last
@scheme[then-expr] are ignored. The results of the last
@scheme[then-expr], which is in tail position with respect to the
@scheme[cond] form, provides the result for the whole @scheme[cond]
form.
Otherwise, the first @scheme[test-expr] is evaluated. If it produces
@scheme[#f], then the result is the same as a @scheme[cond] form with
the remaining @scheme[cond-clause]s, in tail position with respect to
the original @scheme[cond] form. Otherwise, evaluation depends on the
form of the @scheme[cond-clause]:
@specsubform[[test-expr then-expr ...+]]{The @scheme[then-expr]s are
evaluated in order, and the results from all but the last
@scheme[then-expr] are ignored. The results of the last
@scheme[then-expr], which is in tail position with respect to the
@scheme[cond] form, provides the result for the whole @scheme[cond]
form.}
@specsubform[#:literals (=>) [test-expr => proc-expr]]{The @scheme[proc-expr] is
evaluated, and it must produce a procedure that accepts on argument,
otherwise the @exnraise[exn:fail:contract]. The procedure is applied
to the result of @scheme[test-expr] in tail position with respect to
the @scheme[cond] expression.}
@specsubform[[test-expr]]{The result of the @scheme[test-expr] is
returned as the result of the @scheme[cond] form. The
@scheme[test-expr] is not in tail position.}
@examples[
(cond)
(cond
[else 5])
(cond
[(positive? -5) (error "doesn't get here")]
[(zero? -5) (error "doesn't get here, either")]
[(positive? 5) 'here])
(cond
[(member 2 '(1 2 3)) => (lambda (l) (map - l))])
(cond
[(member 2 '(1 2 3))])
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:and+or"]{Boolean Combination: @scheme[and] and @scheme[or]}
@guideintro["guide:and+or"]{@scheme[and] and @scheme[or]}
@defform[(and expr ...)]{
If no @scheme[expr]s are provided, then result is @scheme[#f].
If a single @scheme[expr] is provided, then it is in tail position, so
the results of the @scheme[and] expression are the results of the
@scheme[expr].
Otherwise, the first @scheme[expr] is evaluated. If it produces
@scheme[#f], the result of the @scheme[and] expression is
@scheme[#f]. Otherwise, the result is the same as an @scheme[and]
expression with the remaining @scheme[expr]s in tail position with
respect to the original @scheme[and] form.
@examples[
(and)
(and 1)
(and (values 1 2))
(and #f (error "doesn't get here"))
(and #t 5)
]}
@defform[(or expr ...)]{
If no @scheme[expr]s are provided, then result is @scheme[#t].
If a single @scheme[expr] is provided, then it is in tail position, so
the results of the @scheme[and] expression are the results of the
@scheme[expr].
Otherwise, the first @scheme[expr] is evaluated. If it produces a
value other than @scheme[#f], that result is the result of the
@scheme[or] expression. Otherwise, the result is the same as an
@scheme[or] expression with the remaining @scheme[expr]s in tail
position with respect to the original @scheme[or] form.
@examples[
(or)
(or 1)
(or (values 1 2))
(or 5 (error "doesn't get here"))
(or #f 5)
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:when+unless"]{Guarded Evaluation: @scheme[when] and @scheme[unless]}
@guideintro["guide:when+unless"]{@scheme[when] and @scheme[unless]}
@defform[(when test-expr expr ...)]{
Evaluates the @scheme[text-expr]. If the result is any value other
than @scheme[#f], the @scheme[expr]s are evaluated, and the results
are ignored. No @scheme[expr] is in tail position with respect to the
@scheme[when] form.
@examples[
(when (positive? -5)
(display "hi"))
(when (positive? 5)
(display "hi")
(display " there"))
]}
@defform[(unless test-expr expr ...)]{
Equivalent to @scheme[(when (not test-expr) expr ...)].
@examples[
(unless (positive? 5)
(display "hi"))
(unless (positive? -5)
(display "hi")
(display " there"))
]}
@;------------------------------------------------------------------------
@include-section["define-struct.scrbl"]
@;------------------------------------------------------------------------
@include-section["for.scrbl"]

View File

@ -281,45 +281,53 @@ position with respect to the @scheme[with-handlers*] form.}
@defstruct[exn ([message string?]
[continuation-marks continuation-mark-set?])
#:immutable]{
#:immutable
#:inspector #f]{
The base @tech{structure type} for exceptions. The @scheme[message]
field contains an error message, and the @scheme[continuation-marks]
field contains the value produced by @scheme[(current-continuation-marks)]
immediately before the exception was raised.}
@defstruct[(exn:fail exn) ()]{
@defstruct[(exn:fail exn) ()
#:inspector #f]{
Raised for exceptions that represent errors, as opposed to
@scheme[exn:break].}
@defstruct[(exn:fail:contract exn:fail) ()]{
@defstruct[(exn:fail:contract exn:fail) ()
#:inspector #f]{
Raised for errors from the inappropriate run-time use of a function or
syntactic form.}
@defstruct[(exn:fail:contract:arity exn:fail:contract) ()]{
@defstruct[(exn:fail:contract:arity exn:fail:contract) ()
#:inspector #f]{
Raised when a procedure is applied to the wrong number of arguments.}
@defstruct[(exn:fail:contract:divide-by-zero exn:fail:contract) ()]{
@defstruct[(exn:fail:contract:divide-by-zero exn:fail:contract) ()
#:inspector #f]{
Raised for division by exact zero.}
@defstruct[(exn:fail:contract:continuation exn:fail:contract) ()]{
@defstruct[(exn:fail:contract:continuation exn:fail:contract) ()
#:inspector #f]{
Raised when a continuation is applied where the jump would cross a
continuation barrier.}
@defstruct[(exn:fail:contract:variable exn:fail:contract) ([id symbol?])
#:immutable]{
#:immutable
#:inspector #f]{
Raised for a reference to a not-yet-defined @tech{top-level variable}
or @tech{module-level variable}.}
@defstruct[(exn:fail:syntax exn:fail) ([exprs (listof syntax?)])
#:immutable]{
#:immutable
#:inspector #f]{
Raised for a syntax error that is not a @scheme[read] error. The
@scheme[exprs] indicate the relevant source expressions,
@ -327,61 +335,103 @@ least-specific to most-specific.}
@defstruct[(exn:fail:read exn:fail) ([srclocs (listof srcloc?)])
#:immutable]{
#:immutable
#:inspector #f]{
Raised for a @scheme[read] error. The @scheme[srclocs] indicate the
relevant source expressions.}
@defstruct[(exn:fail:read:eof exn:fail:read) ()]{
@defstruct[(exn:fail:read:eof exn:fail:read) ()
#:inspector #f]{
Raised for a @scheme[read] error, specifically when the error is due
to an unexpected end-of-file.}
@defstruct[(exn:fail:read:non-char exn:fail:read) ()]{
@defstruct[(exn:fail:read:non-char exn:fail:read) ()
#:inspector #f]{
Raised for a @scheme[read] error, specifically when the error is due
to an unexpected non-character (i.e., ``special'') element in the
input stream.}
@defstruct[(exn:fail:filesystem exn:fail) ()]{
@defstruct[(exn:fail:filesystem exn:fail) ()
#:inspector #f]{
Raised for an error related to the filesystem (such as a file not
found).}
@defstruct[(exn:fail:filesystem:exists exn:fail:filesystem) ()]{
@defstruct[(exn:fail:filesystem:exists exn:fail:filesystem) ()
#:inspector #f]{
Raised for an error when attempting to create a file that exists
already.}
@defstruct[(exn:fail:filesystem:version exn:fail:filesystem) ()]{
@defstruct[(exn:fail:filesystem:version exn:fail:filesystem) ()
#:inspector #f]{
Raised for a version-mismatch error when loading an extension.}
@defstruct[(exn:fail:network exn:fail) ()]{
@defstruct[(exn:fail:network exn:fail) ()
#:inspector #f]{
Raised for TCP and UDP errors.}
@defstruct[(exn:fail:out-of-memory exn:fail) ()]{
@defstruct[(exn:fail:out-of-memory exn:fail) ()
#:inspector #f]{
Raised for an error due to insufficient memory, in cases where sufficient
memory is at least available for raising the exception.}
@defstruct[(exn:fail:unsupported exn:fail) ()]{
@defstruct[(exn:fail:unsupported exn:fail) ()
#:inspector #f]{
Raised for an error due to an unsupported feature on the current
platform or configuration.}
@defstruct[(exn:fail:user exn:fail) ()]{
@defstruct[(exn:fail:user exn:fail) ()
#:inspector #f]{
Raised for errors that are intended to be seen by end-users. In
particular, the default error printer does not show the program
context when printing the error message.}
@defstruct[(exn:break exn) ([continuation continuation?])
#:immutable]{
#:immutable
#:inspector #f]{
Raised asynchronously (when enabled) in response to a break request.
The @scheme[continuation] field can be used by a handler to resume the
interrupted computation.}
@defstruct[srcloc ([source any/c]
[line (or/c positive-exact-integer? false/c)]
[column (or/c nonnegative-exact-integer? false/c)]
[position (or/c positive-exact-integer? false/c)]
[span (or/c nonnegative-exact-integer? false/c)])
#:immutable
#:inspector #f]{
The fields of an @scheme[srcloc] instance are as follows:
@itemize{
@item{@scheme[source] --- An arbitrary value identifying the source,
often a path (see @secref["mz:pathutils"]).}
@item{@scheme[line] --- The line number (counts from 1) or
@scheme[#f] (unknown).}
@item{@scheme[column] --- The column number (counts from 0) or
@scheme[#f] (unknown).}
@item{@scheme[position] --- The starting position (counts from 1) or
@scheme[#f] (unknown).}
@item{@scheme[span] --- The number of covered positions (counts from
0) or @scheme[#f] (unknown).}
}}

View File

@ -7,3 +7,8 @@
@local-table-of-contents[]
@include-section["ports.scrbl"]
@include-section["string-input.scrbl"]
@include-section["string-output.scrbl"]
@include-section["read.scrbl"]
@include-section["write.scrbl"]
@include-section["reader.scrbl"]

View File

@ -634,14 +634,14 @@ escape-continuation aborts can cross continuation barriers.
@;------------------------------------------------------------------------
@section[#:tag "mz:thread-model"]{Threads}
Scheme supports multiple, pre-emptive threads of evaluation. In terms
of the evaluation model, this means that each step in evaluation
actually consists of multiple concurrent expressions, rather than a
single expression. The expressions all share the same objects and
top-level variables, so that they can communicate through shared
state. Most evaluation steps involve a single step in a single
expression, but certain synchronization primitives require multiple
threads to progress together in one step.
Scheme supports multiple, pre-emptive @deftech{threads} of
evaluation. In terms of the evaluation model, this means that each
step in evaluation actually consists of multiple concurrent
expressions, rather than a single expression. The expressions all
share the same objects and top-level variables, so that they can
communicate through shared state. Most evaluation steps involve a
single step in a single expression, but certain synchronization
primitives require multiple threads to progress together in one step.
In addition to the state that is shared among all threads, each thread
has its own private state that is accessed through @deftech{thread

View File

@ -37,9 +37,6 @@ the port becomes unknown, and line and column tacking is disabled.
Return-linefeed combinations are treated as a single character
position only when line and column counting is enabled.
Certain kinds of exceptions (see @secref["mz:exns"]) encapsulate
source-location information using a @scheme[srcloc] structure.
@;------------------------------------------------------------------------
@defproc[(port-count-lines! [port port?]) void?]{
@ -64,32 +61,3 @@ read from or written to the port, but if line/character counting is
enabled for @scheme[port], the column and position results can
decrease after reading or writing a byte that ends a UTF-8 encoding
sequence.}
@defstruct[srcloc ([source any/c]
[line (or/c positive-exact-integer? false/c)]
[column (or/c nonnegative-exact-integer? false/c)]
[position (or/c positive-exact-integer? false/c)]
[span (or/c nonnegative-exact-integer? false/c)])
#:immutable
#:inspector #f]{
The fields of an @scheme[srcloc] instance are as follows:
@itemize{
@item{@scheme[source] --- An arbitrary value identifying the source,
often a path (see @secref["mz:pathutils"]).}
@item{@scheme[line] --- The line number (counts from 1) or
@scheme[#f] (unknown).}
@item{@scheme[column] --- The column number (counts from 0) or
@scheme[#f] (unknown).}
@item{@scheme[position] --- The starting position (counts from 1) or
@scheme[#f] (unknown).}
@item{@scheme[span] --- The number of covered positions (counts from
0) or @scheme[#f] (unknown).}
}}

View File

@ -53,5 +53,5 @@ terminal, @scheme[#f] otherwise.}
@defthing[eof eof-object?]{A value (distinct from all other values)
that represents an end-of-file.}
@defproc[(eof-object [a any/c]) boolean?]{Returns @scheme[#t] is
@defproc[(eof-object? [a any/c]) boolean?]{Returns @scheme[#t] is
@scheme[v] is @scheme[eof], @scheme[#f] otherwise.}

View File

@ -1,722 +1,198 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@require[(lib "bnf.ss" "scribble")]
@require["reader-example.ss"]
@begin[
(define (ilitchar s)
(litchar s))
(define (nunterm s)
(nonterm s (subscript "n")))
(define (sub n) (subscript n))
(define (nonalpha)
@elem{; the next character must not be @schemelink[char-alphabetic?]{alphabetic}.})
]
@define[(graph-tag) @kleenerange[1 8]{@nonterm{digit@sub{10}}}]
@define[(graph-defn) @elem{@litchar{#}@graph-tag[]@litchar{=}}]
@define[(graph-ref) @elem{@litchar{#}@graph-tag[]@litchar{#}}]
@title[#:tag "mz:reader"]{Reading}
Scheme's reader is a recursive-descent parser that can be configured
through a @seclink["mz:readtables"]{readtable} and various other
@tech{parameters}. This section describes the reader's parsing when
using the default readtable.
Reading from a stream produces one @defterm{datum}. If the result
datum is a compound value, then reading the datum typically requires
the reader to call itself recursively to read the component data.
The reader can be invoked in either of two modes: @scheme[read] mode,
or @scheme[read-syntax] mode. In @scheme[read-syntax] mode, the result
is always a @techlink{syntax object} that includes
source-location and (initially empty) lexical information wrapped
around the sort of datum that @scheme[read] mode would produce. In the
case of pairs, vectors, and boxes, morever, the content is also
wrapped recursively as a syntax object. Unless specified otherwise,
this section describes the reader's behavior in @scheme[read] mode,
and @scheme[read-syntax] mode does the same modulo wrapping the final
result.
Reading is defined in terms of Unicode characters; see
@secref["mz:char-input"] for information on how a byte stream is converted
to a character stream.
@section[#:tag "mz:default-readtable-dispatch"]{Delimiters and Dispatch}
Along with @schemelink[char-whitespace?]{whitespace}, the following
characters are @defterm{delimiters}:
@t{
@hspace[2] @ilitchar{(} @ilitchar{)} @ilitchar{[} @ilitchar{]}
@ilitchar["["] @ilitchar["]"]
@ilitchar{"} @ilitchar{,} @ilitchar{'} @ilitchar{`}
@ilitchar{;}
}
A delimited sequence that starts with any other character is typically
parsed as either a symbol or number, but a few non-delimiter
characters play special roles:
@itemize{
@title{Reading}
@defproc[(read [in input-port? (current-input-port)]) any]{
Reads and returns a single @tech{datum} from @scheme[in]. If
@scheme[in] has a handler associated to it via
@scheme[port-read-handler], then the handler is called. Otherwise, the
default reader is used, as parameterized by the
@scheme[current-readtable] parameter, as well as many other
parameters.
See @secref["mz:reader"] for information on the default reader.}
@defproc[(read-syntax [source-name any/c (object-name in)]
[in input-port? (current-input-port)])
(or/c syntax? eof-object?)]{
Like @scheme[read], but produces a @tech{syntax object} with
source-location information. The @scheme[source-name] is used as the
source field of the syntax object; it can be an arbitrary value, but
it should generally be a path for the source file.
See @secref["mz:reader"] for information on the default reader in
@scheme[read-syntax] mode.}
@defproc[(read/recursive [in input-port? (current-input-port)]
[start (or/c character? false/c) #f]
[readtable readtable? (current-readtable)]
[graph? any/c #f])
any]{
Similar to calling @scheme[read], but normally used during the dynamic
extent of @scheme[read] within a reader-extension procedure (see
@secref["mz:reader-procs"]). The main effect of using
@scheme[read/recursive] instead of @scheme[read] is that
graph-structure annotations (see @secref["mz:sexpressions"]) in the
nested read are considered part of the overall read, at least when the
@scheme[graph?] argument is true; since the result is wrapped in a
placeholder, however, it is not directly inspectable.
If @scheme[start] is provided and not @scheme[#f], it is effectively
prefixed to the beginning of @scheme[in]'s stream for the read. (To
prefix multiple characters, use @scheme[input-port-append].)
The @scheme[readtable] argument is used for top-level parsing to
satisfy the read request; recursive parsing within the read (e.g., to
read the elements of a list) instead uses the current readtable as
determined by the @scheme[current-readtable] parameter. A reader
macro might call @scheme[read/recursive] with a character and
readtable to effectively invoke the readtable's behavior for the
character. If @scheme[readtable] is @scheme[#f], the default
readtable is used for top-level parsing.
When @scheme[graph?] is @scheme[#f], graph structure annotations in
the read datum are local to the datum.
When called within the dynamic extent of @scheme[read], the
@scheme[read/recursive] procedure produces either an opaque
placeholder value, a special-comment value, or an end-of-file. The
result is a special-comment value (see @secref["mz:special-comments"])
when the input stream's first non-whitespace content parses as a
comment. The result is end-of-file when @scheme[read/recursive]
encounters an end-of-file. Otherwise, the result is a placeholder that
protects graph references that are not yet resolved. When this
placeholder is returned within an S-expression that is produced by any
reader-extension procedure (see @secref["mz:reader-procs"]) for the
same outermost @scheme[read], it will be replaced with the actual read
value before the outermost @scheme[read] returns.
See @secref["mz:readtables"] for an extended example that uses
@scheme[read/recursive].}
@defproc[(read-syntax/recursive [source-name any/c (object-name in)]
[in input-port? (current-input-port)]
[start (or/c character? false/c) #f]
[readtable readtable? (current-readtable)]
[graph? any/c #f])
any]{
Analogous to calling @scheme[read/recursive], but the resulting value
encapsulates S-expression structure with source-location
information. As with @scheme[read/recursive], when
@scheme[read-syntax/recursive] is used within the dynamic extent of
@scheme[read-syntax], the result of from
@scheme[read-syntax/recursive] is either a special-comment value,
end-of-file, or opaque graph-structure placeholder (not a syntax
object). The placeholder can be embedded in an S-expression or syntax
object returned by a reader macro, etc., and it will be replaced with
the actual syntax object before the outermost @scheme[read-syntax]
returns.
Using @scheme[read/recursive] within the dynamic extent of
@scheme[read-syntax] does not allow graph structure for reading to be
included in the outer @scheme[read-syntax] parsing, and neither does
using @scheme[read-syntax/recursive] within the dynamic extent of
@scheme[read]. In those cases, @scheme[read/recursive] and
@scheme[read-syntax/recursive] produce results like @scheme[read] and
@scheme[read-syntax], except that a special-comment value is returned
when the input stream starts with a comment (after whitespace).
See @secref["mz:readtables"] for an extended example that uses
@scheme[read-syntax/recursive].}
@defboolparam[read-case-sensitive on?]{
A parameter that controls parsing and printing of symbols. When this
parameter's value is @scheme[#f], the reader case-folds symbols (e.g.,
producing @scheme['hi] when the input is any one of \litchar{hi},
\litchar{Hi}, \litchar{HI}, or \litchar{hI}). The parameter also
affects the way that @scheme[write] prints symbols containing
uppercase characters; if the parameter's value is @scheme[#f], then
symbols are printed with uppercase characters quoted by a
@litchar["\\"] or @litchar["|"]. The parameter's value is overridden by
quoting @litchar["\\"] or @litchar["|"] vertical-bar quotes and the
@litchar{#cs} and @litchar{#ci} prefixes; see
@secref["mz:parse-symbol"] for more information. While a module is
loaded, the parameter is set to @scheme[#t] (see
@secref["mz:modloadhandler"]).}
@defboolparam[read-square-bracket-as-paren on?]{
A parameter that controls whether @litchar["["] and @litchar["]"]
are treated as parentheses. See @secref["mz:parse-pair"] for more
information.}
@defboolparam[read-curly-brace-as-paren on?]{
A parameter that controls whether @litchar["{"] and @litchar["}"]
are treated as parentheses. See @secref["mz:parse-pair"] for more
information.}
@defboolparam[read-accept-box on?]{
A parameter that controls parsing @litchar{#&} input. See
@secref["mz:parse-box"] for more information.}
@item{@litchar{#} has a special meaning as an initial character in a
delimited sequence; its meaning depends on the characters that
follow; see below.}
@defboolparam[read-accept-compiled on?]{
@item{@as-index{@litchar["|"]} starts a subsequence of characters to
be included verbatim in the delimited sequence (i.e,. they are
never treated as delimiters, and they are not case-folded when
case-insensitivity is enabled); the subsequence is terminated
by another @litchar["|"], and neither the initial nor
terminating @litchar["|"] is part of the subsequence.}
@item{@as-index{@litchar["\\"]} outside of a @litchar["|"] pair causes
the folowing character to be included verbatim in a delimited
sequence.}
}
More precisely, after skipping whitespace, the reader dispatches based
on the next character or characters in the input stream as follows:
@dispatch-table[
@dispatch[@litchar{(}]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar{[}]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar["{"]]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar{)}]{matches @litchar{(} or raises @Exn{exn:fail:read}}
@dispatch[@litchar{]}]{matches @litchar{[} or raises @Exn{exn:fail:read}}
@dispatch[@litchar["}"]]{matches @litchar["{"] or raises @Exn{exn:fail:read}}
@dispatch[@litchar{"}]{starts a string; see @secref["mz:parse-string"]}
@dispatch[@litchar{,}]{starts a quote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{`}]{starts a quasiquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{,}]{starts an unquote or splicing unquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{;}]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@cilitchar{#t}]{true; see @secref["mz:parse-boolean"]}
@dispatch[@cilitchar{#f}]{false; see @secref["mz:parse-boolean"]}
@dispatch[@litchar{#(}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar{#[}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar["#{"]]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar["#\\"]]{starts a character; see @secref["mz:parse-character"]}
@dispatch[@litchar{#"}]{starts a byte string; see @secref["mz:parse-string"]}
@dispatch[@litchar{#%}]{starts a symbol; see @secref["mz:parse-symbol"]}
@dispatch[@litchar{#:}]{starts a keyword; see @secref["mz:parse-keyword"]}
@dispatch[@litchar{#&}]{starts a box; see @secref["mz:parse-box"]}
@dispatch[@litchar["#|"]]{starts a block comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar["#;"]]{starts an S-expression comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar{#,}]{starts a syntax quote; see @secref["mz:parse-quote"]}
@dispatch[@litchar["#! "]]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar["#!/"]]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar{#`}]{starts a syntax quasiquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{#,}]{starts an syntax unquote or splicing unquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar["#~"]]{starts compiled code; see @secref["compilation"]}
@dispatch[@cilitchar{#i}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#e}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#x}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#o}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#d}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#b}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar["#<<"]]{starts a string; see @secref["mz:parse-string"]}
@dispatch[@litchar{#rx}]{starts a regular expression; see @secref["mz:parse-regexp"]}
@dispatch[@litchar{#px}]{starts a regular expression; see @secref["mz:parse-regexp"]}
@dispatch[@cilitchar{#ci}]{switches case sensitivity; see @secref["mz:parse-symbol"]}
@dispatch[@cilitchar{#cs}]{switches case sensitivity; see @secref["mz:parse-symbol"]}
@dispatch[@cilitchar["#sx"]]{starts a Scheme expression; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#hx"]]{starts a Honu expression; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#honu"]]{starts a Honu module; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#hash"]]{starts a hash table; see @secref["mz:parse-hashtable"]}
@dispatch[@litchar["#reader"]]{starts a reader extension use; see @secref["mz:parse-reader"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{(}}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{[}}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar["{"]}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@graph-defn[]]{binds a graph tag; see @secref["mz:parse-graph"]}
@dispatch[@graph-ref[]]{uses a graph tag; see @secref["mz:parse-graph"]}
@dispatch[@italic{otherwise}]{starts a symbol; see @secref["mz:parse-symbol"]}
]
@section[#:tag "mz:parse-symbol"]{Reading Symbols}
@guideintro["guide:symbols"]{the syntax of symbols}
A sequence that does not start with a delimiter or @litchar{#} is
parsed as either a symbol or a number (see @secref["mz:parse-number"]),
except that @litchar{.} by itself is never parsed as a symbol or
character. A @as-index{@litchar{#%}} also starts a symbol. A successful
number parse takes precedence over a symbol parse.
When the @scheme[read-case-sensitive] @tech{parameter} is set to @scheme[#f],
characters in the sequence that are not quoted by @litchar["|"] or
@litchar["\\"] are first case-normalized. If the reader encounters
@as-index{@litchar{#ci}}, @litchar{#CI}, @litchar{#Ci}, or @litchar{#cI},
then it recursively reads the following datum in
case-insensitive mode. If the reader encounters @as-index{@litchar{#cs}},
@litchar{#CS}, @litchar{#Cs}, or @litchar{#cS}, then recursively reads
the following datum in case-sensitive mode.
@reader-examples[#:symbols? #f
"Apple"
"Ap#ple"
"Ap ple"
"Ap| |ple"
"Ap\\ ple"
"#ci Apple"
"#ci |A|pple"
"#ci \\Apple"
"#ci#cs Apple"
"#%Apple"
]
@section[#:tag "mz:parse-number"]{Reading Numbers}
@guideintro["guide:numbers"]{the syntax of numbers}
@index['("numbers" "parsing")]{A} sequence that does not start with a
delimiter is parsed as a number when it matches the following grammar
case-insenstively for @nonterm{number@sub{10}} (decimal), where
@metavar{n} is a meta-meta-variable in the grammar.
A number is optionally prefixed by an exactness specifier,
@as-index{@litchar{#e}} (exact) or @as-index{@litchar{#i}} (inexact),
which specifies its parsing as an exact or inexact number; see
@secref["mz:numbers"] for information on number exactness. As the
non-terminal names suggest, a number that has no exactness specifier
and matches only @nunterm{inexact-number} is normally parsed as an
inexact number, otherwise it is parsed as an excat number. If the
@scheme[read-decimal-as-inexact] @tech{parameter} is set to @scheme[#f], then
all numbers without an exactness specifier are instead parsed as
exact.
If the reader encounters @as-index{@litchar{#b}} (binary),
@as-index{@litchar{#o}} (octal), @as-index{@litchar{#d}} (decimal), or
@as-index{@litchar{#x}} (hexadecimal), it must be followed by a
sequence that is terminated by a delimiter or end-of-file, and that
matches the @nonterm{general-number@sub{2}},
@nonterm{general-number@sub{8}}, @nonterm{general-number@sub{10}}, or
@nonterm{general-number@sub{16}} grammar, respectively.
An @nunterm{exponent-mark} in an inexact number serves both to specify
an exponent and specify a numerical precision. If single-precision
IEEE floating point is supported (see @secref["mz:numbers"]), the marks
@litchar{f} and @litchar{s} specifies single-precision. Otherwise, or
with any other mark, double-precision IEEE floating point is used.
@BNF[(list @nunterm{number} @BNF-alt[@nunterm{exact}
@nunterm{inexact}])
(list @nunterm{exact} @BNF-alt[@nunterm{exact-integer}
@nunterm{exact-rational}]
@nunterm{exact-complex})
(list @nunterm{exact-integer} @BNF-seq[@optional{@nonterm{sign}} @nunterm{digits}])
(list @nunterm{digits} @kleeneplus{@nunterm{digit}})
(list @nunterm{exact-rational} @BNF-seq[@nunterm{exact-integer} @litchar{/} @nunterm{unsigned-integer}])
(list @nunterm{exact-complex} @BNF-seq[@nunterm{exact-rational} @nonterm{sign} @nunterm{exact-rational} @litchar{i}])
(list @nunterm{inexact} @BNF-alt[@nunterm{inexact-real}
@nunterm{inexact-complex}])
(list @nunterm{inexact-real} @BNF-seq[@optional{@nonterm{sign}} @nunterm{inexact-normal}]
@BNF-seq[@nonterm{sign} @nunterm{inexact-special}])
(list @nunterm{inexact-unsigned} @BNF-alt[@nunterm{inexact-normal}
@nunterm{inexact-special}])
(list @nunterm{inexact-normal} @BNF-seq[@nunterm{inexact-simple} @optional{@nunterm{exp-mark}
@optional[@nonterm{sign}] @nunterm{digits#}}])
(list @nunterm{inexact-simple} @BNF-seq[@nunterm{digits#} @optional{@litchar{.}} @kleenestar{@litchar{#}}]
@BNF-seq[@optional{@nunterm{exact-integer}} @litchar{.} @nunterm{digits#}]
@BNF-seq[@nunterm{digits#} @litchar{/} @nunterm{digits#}])
(list @nunterm{inexact-special} @BNF-alt[@litchar{inf.0} @litchar{nan.0}])
(list @nunterm{digits#} @BNF-seq[@kleeneplus{@nunterm{digit}} @kleenestar{@litchar{#}}])
(list @nunterm{inexact-complex} @BNF-seq[@optional{@nunterm{inexact-real}} @nonterm{sign} @nunterm{inexact-unsigned} @litchar{i}]
@BNF-seq[@nunterm{inexact-real} @litchar["@"] @nunterm{inexact-real}])
(list @nonterm{sign} @BNF-alt[@litchar{+}
@litchar{-}])
(list @nonterm{digit@sub{16}} @BNF-alt[@nonterm{digit@sub{10}} @litchar{a} @litchar{b} @litchar{c} @litchar{d}
@litchar{e} @litchar{f}])
(list @nonterm{digit@sub{10}} @BNF-alt[@nonterm{digit@sub{8}} @litchar{8} @litchar{9}])
(list @nonterm{digit@sub{8}} @BNF-alt[@nonterm{digit@sub{2}} @litchar{2} @litchar{3}
@litchar{4} @litchar{5} @litchar{6} @litchar{7}])
(list @nonterm{digit@sub{2}} @BNF-alt[@litchar{0} @litchar{1}])
(list @nonterm{exp-mark@sub{16}} @BNF-alt[@litchar{s} @litchar{d} @litchar{l}])
(list @nonterm{exp-mark@sub{10}} @BNF-alt[@nonterm{exp-mark@sub{16}} @litchar{e} @litchar{f}])
(list @nonterm{exp-mark@sub{8}} @nonterm{exp-mark@sub{10}})
(list @nonterm{exp-mark@sub{2}} @nonterm{exp-mark@sub{10}})
(list @nunterm{general-number} @BNF-seq[@optional{@nonterm{exactness}} @nunterm{number}])
(list @nonterm{exactness} @BNF-alt[@litchar{#e} @litchar{#i}])
]
@reader-examples[
"-1"
"1/2"
"1.0"
"1+2i"
"1/2+3/4i"
"1.0+3.0e7i"
"2e5"
"#i5"
"#e2e5"
"#x2e5"
"#b101"
]
@section[#:tag "mz:parse-boolean"]{Reading Booleans}
A @as-index{@litchar{#t}} or @as-index{@litchar{#T}} is the complete
input syntax for the boolean constant true, and
@as-index{@litchar{#f}} or @as-index{@litchar{#F}} is the complete
input syntax for the boolean constant false.
@section[#:tag "mz:parse-pair"]{Reading Pairs and Lists}
When the reader encounters a @as-index{@litchar{(}},
@as-index{@litchar["["]}, or @as-index{@litchar["{"]}, it starts
parsing a pair or list; see @secref["mz:pairs"] for information on pairs
and lists.
To parse the pair or list, the reader recursively reads data
until a matching @as-index{@litchar{)}}, @as-index{@litchar{]}}, or
@as-index{@litchar["}"]} (respectively) is found, and it specially handles
a delimited @litchar{.}. Pairs @litchar{()}, @litchar{[]}, and
@litchar["{}"] are treated the same way, so the remainder of this
section simply uses ``parentheses'' to mean any of these pair.
If the reader finds no delimited @as-index{@litchar{.}} among the elements
between parentheses, then it produces a list containing the results of
the recursive reads.
If the reader finds two data between the matching parentheses
that are separated by a delimited @litchar{.}, then it creates a
pair. More generally, if it finds two or more data where the
last is preceeded by a delimited @litchar{.}, then it constructs
nested pairs: the next-to-last element is paired with the last, then
the third-to-last is paired with that pair, and so on.
If the reader finds three or more data between the matching
parentheses, and if a pair of delimited @litchar{.}s surrounds any
oter than the first and last elements, the result is a list
countaining the element surrounded by @litchar{.}s as the first
element, followed by the others in ther read order. This convention
supports a kind of @index["infix"]{infix} notation at the reader
level.
In @scheme[read-syntax] mode, the recursive reads for the pair/list
elements are themselves in @scheme[read-syntax] mode, so that the
result is list or pair of syntax objects that it itself wrapped as a
syntax object. If the reader constructs nested pairs because the input
included a single delimited @litchar{.}, then only the innermost pair
and outtermost pair are wrapped as syntax objects. Whether wrapping a
pair or list, if the pair or list was formed with @litchar{[} and
@litchar{]}, then a @scheme['paren-shape] property is attached to the
result with the value @scheme[#\[];if the list or pair was formed with
@litchar["{"] and @litchar["}"], then a @scheme['paren-shape] property
is attached to the result with the value @scheme[#\{].
If a delimited @litchar{.} appears in any other configuration, then
the @exnraise[exn:fail:read]. Similarly, if the reader encounters a
@litchar{)}, @litchar["]"], or @litchar["}"] that does not end a list
being parsed, then the @exnraise[exn:fail:read].
@reader-examples[
"()"
"(1 2 3)"
"{1 2 3}"
"[1 2 3]"
"(1 (2) 3)"
"(1 . 3)"
"(1 . (3))"
"(1 . 2 . 3)"
]
If the @scheme[read-square-bracket-as-paren] @tech{parameter} is set to
@scheme[#f], then when then reader encounters @litchar{[} and
@litchar{]}, the @exnraise{exn:fail:read}. Similarly, If the
@scheme[read-curly-brace-as-paren] @tech{parameter} is set to @scheme[#f],
then when then reader encounters @litchar["{"] and @litchar["}"], the
@exnraise{exn:fail:read}.
@section[#:tag "mz:parse-string"]{Reading Strings}
@guideintro["guide:strings"]{the syntax of strings}
@index['("strings" "parsing")]{When} the reader encouters
@as-index{@litchar{"}}, it begins parsing characters to form a string. The
string continues until it is terminated by another @litchar{"} (that
is not escaped by @litchar["\\"]).
Within a string sequence, the following escape sequences are
recognized:
@itemize{
@item{@as-index{@litchar["\\a"]}: alarm (ASCII 7)}
@item{@as-index{@litchar["\\b"]}: backspace (ASCII 8)}
@item{@as-index{@litchar["\\t"]}: tab (ASCII 9)}
@item{@as-index{@litchar["\\n"]}: linefeed (ASCII 10)}
@item{@as-index{@litchar["\\v"]}: vertical tab (ASCII 11)}
@item{@as-index{@litchar["\\f"]}: formfeed (ASCII 12)}
@item{@as-index{@litchar["\\r"]}: return (ASCII 13)}
@item{@as-index{@litchar["\\e"]}: escape (ASCII 27)}
@item{@as-index{@litchar["\\\""]}: double-quotes (without terminating the string)}
@item{@as-index{@litchar["\\'"]}: quote (i.e., the backslash has no effect)}
@item{@as-index{@litchar["\\\\"]}: backslash (i.e., the second is not an escaping backslash)}
@item{@as-index{@litchar["\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}}:
Unicode for the octal number specified by @kleenerange[1
3]{digit@sub{8}} (i.e., 1 to 3 @nonterm{digit@sub{8}}s) where
each @nonterm{digit@sub{8}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, or @litchar{7}. A longer form takes precedence
over a shorter form, and the resulting octal number must be
between 0 and 255 decimal, otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\x"]@kleenerange[1
2]{@nonterm{digit@sub{16}}}}: Unicode for the hexadecimal
number specified by @kleenerange[1 2]{@nonterm{digit@sub{16}}},
where each @nonterm{digit@sub{16}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, @litchar{7}, @litchar{8}, @litchar{9},
@litchar{a}, @litchar{b}, @litchar{c}, @litchar{d},
@litchar{e}, or @litchar{f} (case-insensitive). The longer form
takes precedence over the shorter form.}
@item{@as-index{@litchar["\\u"]@kleenerange[1
4]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to four hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\U"]@kleenerange[1
8]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to eight hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\"]@nonterm{newline}}: elided, where
@nonterm{newline} is either a linefeed, carriage return, or
carriage return--linefeed combination. This convetion allows
single-line strings to span multiple lines in the source.}
}
If the reader encounteres any other use of a backslash in a string
constant, the @exnraise[exn:fail:read].
@guideintro["guide:bytestrings"]{the syntax of byte strings}
@index['("byte strings" "parsing")]{A} string constant preceded by
@litchar{#} is parsed as a byte-string. (That is, @as-index{@litchar{#"}} starts
a byte-string literal.) See @secref["mz:bytestrings"] for
information on byte strings. Byte string constants support the same
escape sequences as character strings, except @litchar["\\u"] and
@litchar["\\U"].
When the reader encounters @as-index{@litchar{#<<}}, it starts parsing a
@pidefterm{here string}. The characters following @litchar{#<<} until
a newline character define a terminator for the string. The content of
the string includes all characters between the @litchar{#<<} line and
a line whose only content is the specified terminator. More precisely,
the content of the string starts after a newline following
@litchar{#<<}, and it ends before a newline that is followed by the
terminator, where the terminator is itself followed by either a
newline or end-of-file. No escape sequences are recognized between the
starting and terminating lines; all characters are included in the
string (and terminator) literally. A return character is not treated
as a line separator in this context. If no characters appear between
@litchar{#<<} and a newline or end-of-file, or if an end-of-file is
encountered before a terminating line, the @exnraise[exn:fail:read].
@reader-examples[
"\"Apple\""
"\"\\x41pple\""
"\"\\\"Apple\\\"\""
"\"\\\\\""
"#\"Apple\""
]
@section[#:tag "mz:parse-quote"]{Reading Quotes}
When the reader enounters @as-index{@litchar{'}}, then it recursively
reads one datum, and it forms a new list containing the symbol
@scheme['quote] and the following datum. This convention is mainly
useful for reading Scheme code, where @scheme['s] can be used as a
shorthand for @scheme[(code:quote s)].
Several other sequences are recognized and transformed in a similar
way. Longer prefixes take precedence over short ones:
@read-quote-table[(list @litchar{'} @scheme[quote])
(list @as-index{@litchar{`}} @scheme[quasiquote])
(list @as-index{@litchar{,}} @scheme[unquote])
(list @as-index{@litchar[",@"]} @scheme[unquote-splicing])
(list @as-index{@litchar{#'}} @scheme[syntax])
(list @as-index{@litchar{#`}} @scheme[quasisyntax])
(list @as-index{@litchar{#,}} @scheme[unsyntax])
(list @as-index{@litchar["#,@"]} @scheme[unsyntax-splicing])]
@reader-examples[
"'apple"
"`(1 ,2)"
]
@section[#:tag "mz:parse-comment"]{Reading Comments}
A @as-index{@litchar{;}} starts a line comment. When the reader
encounters @litchar{;}, then it skips past all characters until the
next linefeed or carriage return.
A @litchar["#|"] starts a nestable block comment. When the reader
encounters @litchar["#|"], then it skips past all characters until a
closing @litchar["|#"]. Pairs of matching @litchar["#|"] and
@litchar["|#"] can be nested.
A @litchar{#;} starts an S-expression comment. Then the reader
encounters @litchar{#;}, it recursively reads one datum, and then
discards the datum (continuing on to the next datum for the read
result).
A @litchar{#! } (which is @litchar{#!} followed by a space) or
@litchar{#!/} starts a line comment that can be continued to the next
line by ending a line with @litchar["\\"]. This form of comment
normally appears at the beginning of a Unix script file.
@reader-examples[
"; comment"
"#| a |# 1"
"#| #| a |# 1 |# 2"
"#;1 2"
"#!/bin/sh"
"#! /bin/sh"
]
@section[#:tag "mz:parse-vector"]{Reading Vectors}
When the reader encounters a @litchar{#(}, @litchar{#[}, or
@litchar["#{"], it starts parsing a vector; see @secref["vectors"] for
information on vectors.
The elements of the vector are recursively read until a matching
@litchar{)}, @litchar{]}, or @litchar["}"] is found, just as for
lists (see @secref["mz:parse-pair"]). A delimited @litchar{.} is not
allowed among the vector elements.
An optional vector length can be specified between the @litchar{#} and
@litchar["("], @litchar["["], or @litchar["{"]. The size is specified
using a sequence of decimal digits, and the number of elements
provided for the vector must be no more than the specified size. If
fewer elements are provided, the last provided element is used for the
remaining vector slots; if no elements are provided, then @scheme[0]
is used for all slots.
In @scheme[read-syntax] mode, each recursive read for the vector
elements is also in @scheme[read-syntax] mode, so that the wrapped
vector's elements are also wraped as syntax objects.
@reader-examples[
"#(1 apple 3)"
"#3(\"apple\" \"banana\")"
"#3()"
]
@section[#:tag "mz:parse-hashtable"]{Reading Hash Tables}
A @litchar{#hash} starts an immutable hash-table constant with key
matching based on @scheme[equal?]. The characters after @litchar{hash}
must parse as a list of pairs (see @secref["mz:parse-pair"]) with a
specific use of delimited @litchar{.}: it must appear between the
elements of each pair in the list, and nowhere in the sequence of list
elements. The first element of each pair is used as the key for a
table entry, and the second element of each pair is the associated
value.
A @litchar{#hasheq} starts a hash table like @litchar{#hash}, except
that it constructs a hash table based on @scheme[eq?] instead of
@scheme[equal?].
In either case, the table is constructed by adding each mapping to the
hash table from left to right, so later mappings can hide earlier
mappings if the keys are equivalent.
@reader-examples[
#:example-note @elem{, where @scheme[make-...] stands for @scheme[make-immutable-hash-table]}
"#hash()"
"#hasheq()"
"#hash((\"a\" . 5))"
"#hasheq((a . 5) (b . 7))"
"#hasheq((a . 5) (a . 7))"
]
@section[#:tag "mz:parse-box"]{Reading Boxes}
When the reader encounters a @litchar{#&}, it starts parsing a box;
see @secref["boxes"] for information on boxes. The content of the box
is determined by recursively reading the next datum.
In @scheme[read-syntax] mode, the recursive read for the box content
is also in @scheme[read-syntax] mode, so that the wrapped box's
content is also wraped as a syntax object.
@reader-examples[
"#&17"
]
@section[#:tag "mz:parse-character"]{Reading Characters}
@guideintro["guide:characters"]{the syntax of characters}
A @litchar["#\\"] starts a character constant, which has one of the
following forms:
@itemize{
@item{ @litchar["#\\nul"] or @litchar["#\\null"]: NUL (ASCII 0)@nonalpha[]}
@item{ @litchar["#\\backspace"]: backspace (ASCII 8)@nonalpha[]}
@item{ @litchar["#\\tab"]: tab (ASCII 9)@nonalpha[]}
@item{ @litchar["#\\newline"] or @litchar["#\\linefeed"]: linefeed (ASCII 10)@nonalpha[]}
@item{ @litchar["#\\vtab"]: vertical tab (ASCII 11)@nonalpha[]}
@item{ @litchar["#\\page"]: page break (ASCII 12)@nonalpha[]}
@item{ @litchar["#\\return"]: carriage return (ASCII 13)@nonalpha[]}
@item{ @litchar["#\\space"]: space (ASCII 32)@nonalpha[]}
@item{ @litchar["#\\rubout"]: delete (ASCII 127)@nonalpha[]}
@item{@litchar["#\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}:
Unicode for the octal number specified by @kleenerange[1
3]{@nonterm{digit@sub{8}}}, as in string escapes (see
@secref["mz:parse-string"]).}
@item{@litchar["#\\x"]@kleenerange[1 2]{@nonterm{digit@sub{16}}}:
Unicode for the hexadecimal number specified by @kleenerange[1
2]{@nonterm{digit@sub{16}}}, as in string escapes (see
@secref["mz:parse-string"]).}
@item{@litchar["#\\u"]@kleenerange[1 4]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to four hexadecimal digits.}
@item{@litchar["#\\U"]@kleenerange[1 6]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to six hexadecimal digits.}
@item{@litchar["#\\"]@nonterm{c}: the character @nonterm{c}, as long
as @litchar["#\\"]@nonterm{c} and the characters following it
do not match any of the previous cases, and as long as the
character after @nonterm{c} is not
@schemelink[char-alphabetic?]{alphabetic}.}
}
@reader-examples[
"#\\newline"
"#\\n"
"#\\u3BB"
"#\\\u3BB"
]
@section[#:tag "mz:parse-keyword"]{Reading Keywords}
A @litchar{#:} starts a keyword. The parsing of a keyword after the
@litchar{#:} is the same as for a symbol, including case-folding in
case-insensitive mode, except that the part after @litchar{#:} is
never parsed as a number.
@reader-examples[
"#:Apple"
"#:1"
]
@section[#:tag "mz:parse-regexp"]{Reading Regular Expressions}
A @litchar{#rx} or @litchar{#px} starts a regular expression. The
characters immediately after @litchar{#rx} or @litchar{#px} must parse
as a string or byte string (see @secref["mz:parse-string"]). A
@litchar{#rx} prefix starts a regular expression as would be
constructed by @scheme[regexp], @litchar{#px} as
constructed by @scheme[pregexp], @litchar{#rx#} as
constructed by @scheme[byte-regexp], and @litchar{#px#} as
constructed by @scheme[byte-pregexp].
@reader-examples[
"#rx\".*\""
"#px\"[\\\\s]*\""
"#rx#\".*\""
"#px#\"[\\\\s]*\""
]
@section[#:tag "mz:parse-graph"]{Reading Graph Structure}
A @graph-defn[] tags the following datum for reference via
@graph-ref[], which allows the reader to produce a datum that
have graph structure.
For a specific @graph-tag in a single read result, each @graph-ref[]
reference is replaced by the datum read for the corresponding
@graph-defn[]; the definition @graph-defn[] also produces just the
datum after it. A @graph-defn[] definition can appear at most
once, and a @graph-defn[] definition must appear before a @graph-ref[]
reference appears.
Although a comment parsed via @litchar{#;} discards the datum
afterward, @graph-defn[] definitions in the discarded datum
still can be referenced by other parts of the reader input, as long as
both the comment and the reference are grouped together by some other
form (i.e., some recursive read); a top-level @litchar{#;} comment
neither defines nor uses graph tags for other top-level forms.
@reader-examples[
"(#1=100 #1# #1#)"
"#0=(1 . #0#)"
]
@section[#:tag "mz:parse-reader"]{Reading via an External Reader}
When the reader encounters @litchar{#reader}, then it loads an
external reader procedure and applies it to the current input stream.
The reader recursively reads the next datum after @litchar{#reader},
and passes it to the procedure that is the value of the
@scheme[current-reader-guard] @tech{parameter}; the result is used as a
module path. The module path is passed to @scheme[dynamic-require]
with either @scheme['read] or @scheme['read-syntax] (depending on
whether the reader is in @scheme[read] or @scheme[read-syntax]
mode).
The resulting procedure should accept the same arguments as
@scheme[read] or @scheme[read-syntax] in the case thar all optional
arguments are provided. The procedure is given the port whose stream
contained @litchar{#reader}, and it should produce a datum result. If
the result is a syntax object in @scheme[read] mode, then it is
converted to a datum using @scheme[syntax-object->datum]; if the
result is not a syntax object in @scheme[read-syntax] mode, then it is
converted to one using @scheme[datum->syntax-object]. See also
@secref["special-comments"] and @secref["recursive-reads"] for
information on special-comment results and recursive reads.
If the @scheme[read-accept-reader] @tech{parameter} is set to @scheme[#f],
then if the reader encounters @litchar{#reader}, the
@exnraise[exn:fail:read].
@section[#:tag "mz:readtables"]{Readtables}
The dispatch table in @secref["mz:default-readtable-dispatch"]
corresponds to the default @idefterm{readtable}.
@section[#:tag "mz:parse-honu"]{Honu Parsing}
A parameter that controls parsing @litchar{#~} compiled input. See
@secref["mz:parsing"] for more information.}
@defboolparam[read-accept-bar-quote on?]{
A parameter that controls parsing and printing of @litchar["|"] in
symbols. See @secref["mz:parse-symbol"] and @secref["mz:printing"] for
more information.}
@defboolparam[read-accept-graph on?]{
A parameter value that controls parsing input with sharing. See
@secref["mz:parse-graph"] for more information.}
@defboolparam[read-decimal-as-inexact on?]{
A parameter that controls parsing input numbers with a decimal point
or exponent (but no explicit exactness tag). See
@secref["mz:parse-number"] for more information.}
@defboolparam[read-accept-dot on?]{
A parameter that controls parsing input with a dot, which is normally
used for literal cons cells. See @secref["mz:parse-pair"] for more
information.}
@defboolparam[read-accept-infix-dot on?]{
A parameter that controls parsing input with two dots to trigger infix
conversion. See @secref["mz:parse-pair"] for more information.}
@defboolparam[read-accept-quasiquote on?]{
A parameter that controls parsing input with @litchar{`} or
@litchar{,} which is normally used for @scheme[quasiquote],
@scheme[unquote], and @scheme[unquote-splicing] abbreviations. See
@secref["mz:parse-quote"] for more information.}
@defboolparam[read-accept-reader on?]{
A parameter that controls whether @litchar{#reader} is allowed for
selecting a parser. See @secref["mz:parse-reader"] for more
information.}
@defparam[current-reader-guard proc (any/c . -> . any)]{
A parameter whose value converts or rejects (by raising an exception)
a module-path datum following @litchar{#reader}. See
@secref["mz:parse-reader"] for more information.}
@defparam[current-readtable readtable (or/c readtable? false/c)]{
A parameter whose value determines a readtable that
adjusts the parsing of S-expression input, where @scheme[#f] implies the
default behavior. See @secref["mz:readtables"] for more information.}

View File

@ -0,0 +1,735 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@require[(lib "bnf.ss" "scribble")]
@require["reader-example.ss"]
@begin[
(define (ilitchar s)
(litchar s))
(define (nunterm s)
(nonterm s (subscript "n")))
(define (sub n) (subscript n))
(define (nonalpha)
@elem{; the next character must not be @schemelink[char-alphabetic?]{alphabetic}.})
]
@define[(graph-tag) @kleenerange[1 8]{@nonterm{digit@sub{10}}}]
@define[(graph-defn) @elem{@litchar{#}@graph-tag[]@litchar{=}}]
@define[(graph-ref) @elem{@litchar{#}@graph-tag[]@litchar{#}}]
@title[#:tag "mz:reader"]{The Reader}
Scheme's reader is a recursive-descent parser that can be configured
through a @seclink["mz:readtables"]{readtable} and various other
@tech{parameters}. This section describes the reader's parsing when
using the default readtable.
Reading from a stream produces one @deftech{datum}. If the result
datum is a compound value, then reading the datum typically requires
the reader to call itself recursively to read the component data.
The reader can be invoked in either of two modes: @scheme[read] mode,
or @scheme[read-syntax] mode. In @scheme[read-syntax] mode, the result
is always a @techlink{syntax object} that includes
source-location and (initially empty) lexical information wrapped
around the sort of datum that @scheme[read] mode would produce. In the
case of pairs, vectors, and boxes, morever, the content is also
wrapped recursively as a syntax object. Unless specified otherwise,
this section describes the reader's behavior in @scheme[read] mode,
and @scheme[read-syntax] mode does the same modulo wrapping the final
result.
Reading is defined in terms of Unicode characters; see
@secref["mz:ports"] for information on how a byte stream is converted
to a character stream.
@;------------------------------------------------------------------------
@section[#:tag "mz:default-readtable-dispatch"]{Delimiters and Dispatch}
Along with @schemelink[char-whitespace?]{whitespace}, the following
characters are @defterm{delimiters}:
@t{
@hspace[2] @ilitchar{(} @ilitchar{)} @ilitchar{[} @ilitchar{]}
@ilitchar["["] @ilitchar["]"]
@ilitchar{"} @ilitchar{,} @ilitchar{'} @ilitchar{`}
@ilitchar{;}
}
A delimited sequence that starts with any other character is typically
parsed as either a symbol or number, but a few non-delimiter
characters play special roles:
@itemize{
@item{@litchar{#} has a special meaning as an initial character in a
delimited sequence; its meaning depends on the characters that
follow; see below.}
@item{@as-index{@litchar["|"]} starts a subsequence of characters to
be included verbatim in the delimited sequence (i.e,. they are
never treated as delimiters, and they are not case-folded when
case-insensitivity is enabled); the subsequence is terminated
by another @litchar["|"], and neither the initial nor
terminating @litchar["|"] is part of the subsequence.}
@item{@as-index{@litchar["\\"]} outside of a @litchar["|"] pair causes
the folowing character to be included verbatim in a delimited
sequence.}
}
More precisely, after skipping whitespace, the reader dispatches based
on the next character or characters in the input stream as follows:
@dispatch-table[
@dispatch[@litchar{(}]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar{[}]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar["{"]]{starts a pair or list; see @secref["mz:parse-pair"]}
@dispatch[@litchar{)}]{matches @litchar{(} or raises @Exn{exn:fail:read}}
@dispatch[@litchar{]}]{matches @litchar{[} or raises @Exn{exn:fail:read}}
@dispatch[@litchar["}"]]{matches @litchar["{"] or raises @Exn{exn:fail:read}}
@dispatch[@litchar{"}]{starts a string; see @secref["mz:parse-string"]}
@dispatch[@litchar{,}]{starts a quote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{`}]{starts a quasiquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{,}]{starts an unquote or splicing unquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{;}]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@cilitchar{#t}]{true; see @secref["mz:parse-boolean"]}
@dispatch[@cilitchar{#f}]{false; see @secref["mz:parse-boolean"]}
@dispatch[@litchar{#(}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar{#[}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar["#{"]]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@litchar["#\\"]]{starts a character; see @secref["mz:parse-character"]}
@dispatch[@litchar{#"}]{starts a byte string; see @secref["mz:parse-string"]}
@dispatch[@litchar{#%}]{starts a symbol; see @secref["mz:parse-symbol"]}
@dispatch[@litchar{#:}]{starts a keyword; see @secref["mz:parse-keyword"]}
@dispatch[@litchar{#&}]{starts a box; see @secref["mz:parse-box"]}
@dispatch[@litchar["#|"]]{starts a block comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar["#;"]]{starts an S-expression comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar{#,}]{starts a syntax quote; see @secref["mz:parse-quote"]}
@dispatch[@litchar["#! "]]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar["#!/"]]{starts a line comment; see @secref["mz:parse-comment"]}
@dispatch[@litchar{#`}]{starts a syntax quasiquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar{#,}]{starts an syntax unquote or splicing unquote; see @secref["mz:parse-quote"]}
@dispatch[@litchar["#~"]]{starts compiled code; see @secref["compilation"]}
@dispatch[@cilitchar{#i}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#e}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#x}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#o}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#d}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar{#b}]{starts a number; see @secref["mz:parse-number"]}
@dispatch[@cilitchar["#<<"]]{starts a string; see @secref["mz:parse-string"]}
@dispatch[@litchar{#rx}]{starts a regular expression; see @secref["mz:parse-regexp"]}
@dispatch[@litchar{#px}]{starts a regular expression; see @secref["mz:parse-regexp"]}
@dispatch[@cilitchar{#ci}]{switches case sensitivity; see @secref["mz:parse-symbol"]}
@dispatch[@cilitchar{#cs}]{switches case sensitivity; see @secref["mz:parse-symbol"]}
@dispatch[@cilitchar["#sx"]]{starts a Scheme expression; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#hx"]]{starts a Honu expression; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#honu"]]{starts a Honu module; see @secref["mz:parse-honu"]}
@dispatch[@litchar["#hash"]]{starts a hash table; see @secref["mz:parse-hashtable"]}
@dispatch[@litchar["#reader"]]{starts a reader extension use; see @secref["mz:parse-reader"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{(}}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{[}}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar["{"]}]{starts a vector; see @secref["mz:parse-vector"]}
@dispatch[@graph-defn[]]{binds a graph tag; see @secref["mz:parse-graph"]}
@dispatch[@graph-ref[]]{uses a graph tag; see @secref["mz:parse-graph"]}
@dispatch[@italic{otherwise}]{starts a symbol; see @secref["mz:parse-symbol"]}
]
@section[#:tag "mz:parse-symbol"]{Reading Symbols}
@guideintro["guide:symbols"]{the syntax of symbols}
A sequence that does not start with a delimiter or @litchar{#} is
parsed as either a symbol or a number (see
@secref["mz:parse-number"]), except that @litchar{.} by itself is
never parsed as a symbol or character (unless the
@scheme[read-accept-dot] parameter is set to @scheme[#f]). A
@as-index{@litchar{#%}} also starts a symbol. A successful number
parse takes precedence over a symbol parse.
When the @scheme[read-case-sensitive] @tech{parameter} is set to @scheme[#f],
characters in the sequence that are not quoted by @litchar["|"] or
@litchar["\\"] are first case-normalized. If the reader encounters
@as-index{@litchar{#ci}}, @litchar{#CI}, @litchar{#Ci}, or @litchar{#cI},
then it recursively reads the following datum in
case-insensitive mode. If the reader encounters @as-index{@litchar{#cs}},
@litchar{#CS}, @litchar{#Cs}, or @litchar{#cS}, then recursively reads
the following datum in case-sensitive mode.
@reader-examples[#:symbols? #f
"Apple"
"Ap#ple"
"Ap ple"
"Ap| |ple"
"Ap\\ ple"
"#ci Apple"
"#ci |A|pple"
"#ci \\Apple"
"#ci#cs Apple"
"#%Apple"
]
@section[#:tag "mz:parse-number"]{Reading Numbers}
@guideintro["guide:numbers"]{the syntax of numbers}
@index['("numbers" "parsing")]{A} sequence that does not start with a
delimiter is parsed as a number when it matches the following grammar
case-insenstively for @nonterm{number@sub{10}} (decimal), where
@metavar{n} is a meta-meta-variable in the grammar.
A number is optionally prefixed by an exactness specifier,
@as-index{@litchar{#e}} (exact) or @as-index{@litchar{#i}} (inexact),
which specifies its parsing as an exact or inexact number; see
@secref["mz:numbers"] for information on number exactness. As the
non-terminal names suggest, a number that has no exactness specifier
and matches only @nunterm{inexact-number} is normally parsed as an
inexact number, otherwise it is parsed as an excat number. If the
@scheme[read-decimal-as-inexact] @tech{parameter} is set to @scheme[#f], then
all numbers without an exactness specifier are instead parsed as
exact.
If the reader encounters @as-index{@litchar{#b}} (binary),
@as-index{@litchar{#o}} (octal), @as-index{@litchar{#d}} (decimal), or
@as-index{@litchar{#x}} (hexadecimal), it must be followed by a
sequence that is terminated by a delimiter or end-of-file, and that
matches the @nonterm{general-number@sub{2}},
@nonterm{general-number@sub{8}}, @nonterm{general-number@sub{10}}, or
@nonterm{general-number@sub{16}} grammar, respectively.
An @nunterm{exponent-mark} in an inexact number serves both to specify
an exponent and specify a numerical precision. If single-precision
IEEE floating point is supported (see @secref["mz:numbers"]), the marks
@litchar{f} and @litchar{s} specifies single-precision. Otherwise, or
with any other mark, double-precision IEEE floating point is used.
@BNF[(list @nunterm{number} @BNF-alt[@nunterm{exact}
@nunterm{inexact}])
(list @nunterm{exact} @BNF-alt[@nunterm{exact-integer}
@nunterm{exact-rational}]
@nunterm{exact-complex})
(list @nunterm{exact-integer} @BNF-seq[@optional{@nonterm{sign}} @nunterm{digits}])
(list @nunterm{digits} @kleeneplus{@nunterm{digit}})
(list @nunterm{exact-rational} @BNF-seq[@nunterm{exact-integer} @litchar{/} @nunterm{unsigned-integer}])
(list @nunterm{exact-complex} @BNF-seq[@nunterm{exact-rational} @nonterm{sign} @nunterm{exact-rational} @litchar{i}])
(list @nunterm{inexact} @BNF-alt[@nunterm{inexact-real}
@nunterm{inexact-complex}])
(list @nunterm{inexact-real} @BNF-seq[@optional{@nonterm{sign}} @nunterm{inexact-normal}]
@BNF-seq[@nonterm{sign} @nunterm{inexact-special}])
(list @nunterm{inexact-unsigned} @BNF-alt[@nunterm{inexact-normal}
@nunterm{inexact-special}])
(list @nunterm{inexact-normal} @BNF-seq[@nunterm{inexact-simple} @optional{@nunterm{exp-mark}
@optional[@nonterm{sign}] @nunterm{digits#}}])
(list @nunterm{inexact-simple} @BNF-seq[@nunterm{digits#} @optional{@litchar{.}} @kleenestar{@litchar{#}}]
@BNF-seq[@optional{@nunterm{exact-integer}} @litchar{.} @nunterm{digits#}]
@BNF-seq[@nunterm{digits#} @litchar{/} @nunterm{digits#}])
(list @nunterm{inexact-special} @BNF-alt[@litchar{inf.0} @litchar{nan.0}])
(list @nunterm{digits#} @BNF-seq[@kleeneplus{@nunterm{digit}} @kleenestar{@litchar{#}}])
(list @nunterm{inexact-complex} @BNF-seq[@optional{@nunterm{inexact-real}} @nonterm{sign} @nunterm{inexact-unsigned} @litchar{i}]
@BNF-seq[@nunterm{inexact-real} @litchar["@"] @nunterm{inexact-real}])
(list @nonterm{sign} @BNF-alt[@litchar{+}
@litchar{-}])
(list @nonterm{digit@sub{16}} @BNF-alt[@nonterm{digit@sub{10}} @litchar{a} @litchar{b} @litchar{c} @litchar{d}
@litchar{e} @litchar{f}])
(list @nonterm{digit@sub{10}} @BNF-alt[@nonterm{digit@sub{8}} @litchar{8} @litchar{9}])
(list @nonterm{digit@sub{8}} @BNF-alt[@nonterm{digit@sub{2}} @litchar{2} @litchar{3}
@litchar{4} @litchar{5} @litchar{6} @litchar{7}])
(list @nonterm{digit@sub{2}} @BNF-alt[@litchar{0} @litchar{1}])
(list @nonterm{exp-mark@sub{16}} @BNF-alt[@litchar{s} @litchar{d} @litchar{l}])
(list @nonterm{exp-mark@sub{10}} @BNF-alt[@nonterm{exp-mark@sub{16}} @litchar{e} @litchar{f}])
(list @nonterm{exp-mark@sub{8}} @nonterm{exp-mark@sub{10}})
(list @nonterm{exp-mark@sub{2}} @nonterm{exp-mark@sub{10}})
(list @nunterm{general-number} @BNF-seq[@optional{@nonterm{exactness}} @nunterm{number}])
(list @nonterm{exactness} @BNF-alt[@litchar{#e} @litchar{#i}])
]
@reader-examples[
"-1"
"1/2"
"1.0"
"1+2i"
"1/2+3/4i"
"1.0+3.0e7i"
"2e5"
"#i5"
"#e2e5"
"#x2e5"
"#b101"
]
@section[#:tag "mz:parse-boolean"]{Reading Booleans}
A @as-index{@litchar{#t}} or @as-index{@litchar{#T}} is the complete
input syntax for the boolean constant true, and
@as-index{@litchar{#f}} or @as-index{@litchar{#F}} is the complete
input syntax for the boolean constant false.
@section[#:tag "mz:parse-pair"]{Reading Pairs and Lists}
When the reader encounters a @as-index{@litchar{(}},
@as-index{@litchar["["]}, or @as-index{@litchar["{"]}, it starts
parsing a pair or list; see @secref["mz:pairs"] for information on pairs
and lists.
To parse the pair or list, the reader recursively reads data
until a matching @as-index{@litchar{)}}, @as-index{@litchar{]}}, or
@as-index{@litchar["}"]} (respectively) is found, and it specially handles
a delimited @litchar{.}. Pairs @litchar{()}, @litchar{[]}, and
@litchar["{}"] are treated the same way, so the remainder of this
section simply uses ``parentheses'' to mean any of these pair.
If the reader finds no delimited @as-index{@litchar{.}} among the elements
between parentheses, then it produces a list containing the results of
the recursive reads.
If the reader finds two data between the matching parentheses
that are separated by a delimited @litchar{.}, then it creates a
pair. More generally, if it finds two or more data where the
last is preceeded by a delimited @litchar{.}, then it constructs
nested pairs: the next-to-last element is paired with the last, then
the third-to-last is paired with that pair, and so on.
If the reader finds three or more data between the matching
parentheses, and if a pair of delimited @litchar{.}s surrounds any
other than the first and last elements, the result is a list
containing the element surrounded by @litchar{.}s as the first
element, followed by the others in the read order. This convention
supports a kind of @index["infix"]{infix} notation at the reader
level.
In @scheme[read-syntax] mode, the recursive reads for the pair/list
elements are themselves in @scheme[read-syntax] mode, so that the
result is list or pair of syntax objects that it itself wrapped as a
syntax object. If the reader constructs nested pairs because the input
included a single delimited @litchar{.}, then only the innermost pair
and outtermost pair are wrapped as syntax objects. Whether wrapping a
pair or list, if the pair or list was formed with @litchar{[} and
@litchar{]}, then a @scheme['paren-shape] property is attached to the
result with the value @scheme[#\[];if the list or pair was formed with
@litchar["{"] and @litchar["}"], then a @scheme['paren-shape] property
is attached to the result with the value @scheme[#\{].
If a delimited @litchar{.} appears in any other configuration, then
the @exnraise[exn:fail:read]. Similarly, if the reader encounters a
@litchar{)}, @litchar["]"], or @litchar["}"] that does not end a list
being parsed, then the @exnraise[exn:fail:read].
@reader-examples[
"()"
"(1 2 3)"
"{1 2 3}"
"[1 2 3]"
"(1 (2) 3)"
"(1 . 3)"
"(1 . (3))"
"(1 . 2 . 3)"
]
If the @scheme[read-square-bracket-as-paren] @tech{parameter} is set to
@scheme[#f], then when then reader encounters @litchar{[} and
@litchar{]}, the @exnraise{exn:fail:read}. Similarly, If the
@scheme[read-curly-brace-as-paren] @tech{parameter} is set to @scheme[#f],
then when then reader encounters @litchar["{"] and @litchar["}"], the
@exnraise{exn:fail:read}.
If the @scheme[read-accept-dot] @tech{parameter} is set to
@scheme[#f], then a delimited @scheme{.} is not treated specially; it
is instead parsed a s symbol. If the @scheme[read-accept-infix-dot]
@tech{parameter} is set to @scheme[#f], then multiple delimited
@litchar{.}s trigger a @scheme[exn:fail:read], instead of the infix
conversion.
@section[#:tag "mz:parse-string"]{Reading Strings}
@guideintro["guide:strings"]{the syntax of strings}
@index['("strings" "parsing")]{When} the reader encouters
@as-index{@litchar{"}}, it begins parsing characters to form a string. The
string continues until it is terminated by another @litchar{"} (that
is not escaped by @litchar["\\"]).
Within a string sequence, the following escape sequences are
recognized:
@itemize{
@item{@as-index{@litchar["\\a"]}: alarm (ASCII 7)}
@item{@as-index{@litchar["\\b"]}: backspace (ASCII 8)}
@item{@as-index{@litchar["\\t"]}: tab (ASCII 9)}
@item{@as-index{@litchar["\\n"]}: linefeed (ASCII 10)}
@item{@as-index{@litchar["\\v"]}: vertical tab (ASCII 11)}
@item{@as-index{@litchar["\\f"]}: formfeed (ASCII 12)}
@item{@as-index{@litchar["\\r"]}: return (ASCII 13)}
@item{@as-index{@litchar["\\e"]}: escape (ASCII 27)}
@item{@as-index{@litchar["\\\""]}: double-quotes (without terminating the string)}
@item{@as-index{@litchar["\\'"]}: quote (i.e., the backslash has no effect)}
@item{@as-index{@litchar["\\\\"]}: backslash (i.e., the second is not an escaping backslash)}
@item{@as-index{@litchar["\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}}:
Unicode for the octal number specified by @kleenerange[1
3]{digit@sub{8}} (i.e., 1 to 3 @nonterm{digit@sub{8}}s) where
each @nonterm{digit@sub{8}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, or @litchar{7}. A longer form takes precedence
over a shorter form, and the resulting octal number must be
between 0 and 255 decimal, otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\x"]@kleenerange[1
2]{@nonterm{digit@sub{16}}}}: Unicode for the hexadecimal
number specified by @kleenerange[1 2]{@nonterm{digit@sub{16}}},
where each @nonterm{digit@sub{16}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, @litchar{7}, @litchar{8}, @litchar{9},
@litchar{a}, @litchar{b}, @litchar{c}, @litchar{d},
@litchar{e}, or @litchar{f} (case-insensitive). The longer form
takes precedence over the shorter form.}
@item{@as-index{@litchar["\\u"]@kleenerange[1
4]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to four hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\U"]@kleenerange[1
8]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to eight hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\"]@nonterm{newline}}: elided, where
@nonterm{newline} is either a linefeed, carriage return, or
carriage return--linefeed combination. This convetion allows
single-line strings to span multiple lines in the source.}
}
If the reader encounteres any other use of a backslash in a string
constant, the @exnraise[exn:fail:read].
@guideintro["guide:bytestrings"]{the syntax of byte strings}
@index['("byte strings" "parsing")]{A} string constant preceded by
@litchar{#} is parsed as a byte-string. (That is, @as-index{@litchar{#"}} starts
a byte-string literal.) See @secref["mz:bytestrings"] for
information on byte strings. Byte string constants support the same
escape sequences as character strings, except @litchar["\\u"] and
@litchar["\\U"].
When the reader encounters @as-index{@litchar{#<<}}, it starts parsing a
@pidefterm{here string}. The characters following @litchar{#<<} until
a newline character define a terminator for the string. The content of
the string includes all characters between the @litchar{#<<} line and
a line whose only content is the specified terminator. More precisely,
the content of the string starts after a newline following
@litchar{#<<}, and it ends before a newline that is followed by the
terminator, where the terminator is itself followed by either a
newline or end-of-file. No escape sequences are recognized between the
starting and terminating lines; all characters are included in the
string (and terminator) literally. A return character is not treated
as a line separator in this context. If no characters appear between
@litchar{#<<} and a newline or end-of-file, or if an end-of-file is
encountered before a terminating line, the @exnraise[exn:fail:read].
@reader-examples[
"\"Apple\""
"\"\\x41pple\""
"\"\\\"Apple\\\"\""
"\"\\\\\""
"#\"Apple\""
]
@section[#:tag "mz:parse-quote"]{Reading Quotes}
When the reader enounters @as-index{@litchar{'}}, then it recursively
reads one datum, and it forms a new list containing the symbol
@scheme['quote] and the following datum. This convention is mainly
useful for reading Scheme code, where @scheme['s] can be used as a
shorthand for @scheme[(code:quote s)].
Several other sequences are recognized and transformed in a similar
way. Longer prefixes take precedence over short ones:
@read-quote-table[(list @litchar{'} @scheme[quote])
(list @as-index{@litchar{`}} @scheme[quasiquote])
(list @as-index{@litchar{,}} @scheme[unquote])
(list @as-index{@litchar[",@"]} @scheme[unquote-splicing])
(list @as-index{@litchar{#'}} @scheme[syntax])
(list @as-index{@litchar{#`}} @scheme[quasisyntax])
(list @as-index{@litchar{#,}} @scheme[unsyntax])
(list @as-index{@litchar["#,@"]} @scheme[unsyntax-splicing])]
@reader-examples[
"'apple"
"`(1 ,2)"
]
The @litchar{`}, @litchar{,}, and @litchar[",@"] forms are disabled when
the @scheme[read-accept-quasiquote] @tech{parameter} is set to
@scheme[#f], in which case the @exnraise[exn:fail:read], instead.
@section[#:tag "mz:parse-comment"]{Reading Comments}
A @as-index{@litchar{;}} starts a line comment. When the reader
encounters @litchar{;}, then it skips past all characters until the
next linefeed or carriage return.
A @litchar["#|"] starts a nestable block comment. When the reader
encounters @litchar["#|"], then it skips past all characters until a
closing @litchar["|#"]. Pairs of matching @litchar["#|"] and
@litchar["|#"] can be nested.
A @litchar{#;} starts an S-expression comment. Then the reader
encounters @litchar{#;}, it recursively reads one datum, and then
discards the datum (continuing on to the next datum for the read
result).
A @litchar{#! } (which is @litchar{#!} followed by a space) or
@litchar{#!/} starts a line comment that can be continued to the next
line by ending a line with @litchar["\\"]. This form of comment
normally appears at the beginning of a Unix script file.
@reader-examples[
"; comment"
"#| a |# 1"
"#| #| a |# 1 |# 2"
"#;1 2"
"#!/bin/sh"
"#! /bin/sh"
]
@section[#:tag "mz:parse-vector"]{Reading Vectors}
When the reader encounters a @litchar{#(}, @litchar{#[}, or
@litchar["#{"], it starts parsing a vector; see @secref["vectors"] for
information on vectors.
The elements of the vector are recursively read until a matching
@litchar{)}, @litchar{]}, or @litchar["}"] is found, just as for
lists (see @secref["mz:parse-pair"]). A delimited @litchar{.} is not
allowed among the vector elements.
An optional vector length can be specified between the @litchar{#} and
@litchar["("], @litchar["["], or @litchar["{"]. The size is specified
using a sequence of decimal digits, and the number of elements
provided for the vector must be no more than the specified size. If
fewer elements are provided, the last provided element is used for the
remaining vector slots; if no elements are provided, then @scheme[0]
is used for all slots.
In @scheme[read-syntax] mode, each recursive read for the vector
elements is also in @scheme[read-syntax] mode, so that the wrapped
vector's elements are also wraped as syntax objects.
@reader-examples[
"#(1 apple 3)"
"#3(\"apple\" \"banana\")"
"#3()"
]
@section[#:tag "mz:parse-hashtable"]{Reading Hash Tables}
A @litchar{#hash} starts an immutable hash-table constant with key
matching based on @scheme[equal?]. The characters after @litchar{hash}
must parse as a list of pairs (see @secref["mz:parse-pair"]) with a
specific use of delimited @litchar{.}: it must appear between the
elements of each pair in the list, and nowhere in the sequence of list
elements. The first element of each pair is used as the key for a
table entry, and the second element of each pair is the associated
value.
A @litchar{#hasheq} starts a hash table like @litchar{#hash}, except
that it constructs a hash table based on @scheme[eq?] instead of
@scheme[equal?].
In either case, the table is constructed by adding each mapping to the
hash table from left to right, so later mappings can hide earlier
mappings if the keys are equivalent.
@reader-examples[
#:example-note @elem{, where @scheme[make-...] stands for @scheme[make-immutable-hash-table]}
"#hash()"
"#hasheq()"
"#hash((\"a\" . 5))"
"#hasheq((a . 5) (b . 7))"
"#hasheq((a . 5) (a . 7))"
]
@section[#:tag "mz:parse-box"]{Reading Boxes}
When the reader encounters a @litchar{#&}, it starts parsing a box;
see @secref["boxes"] for information on boxes. The content of the box
is determined by recursively reading the next datum.
In @scheme[read-syntax] mode, the recursive read for the box content
is also in @scheme[read-syntax] mode, so that the wrapped box's
content is also wraped as a syntax object.
@reader-examples[
"#&17"
]
@section[#:tag "mz:parse-character"]{Reading Characters}
@guideintro["guide:characters"]{the syntax of characters}
A @litchar["#\\"] starts a character constant, which has one of the
following forms:
@itemize{
@item{ @litchar["#\\nul"] or @litchar["#\\null"]: NUL (ASCII 0)@nonalpha[]}
@item{ @litchar["#\\backspace"]: backspace (ASCII 8)@nonalpha[]}
@item{ @litchar["#\\tab"]: tab (ASCII 9)@nonalpha[]}
@item{ @litchar["#\\newline"] or @litchar["#\\linefeed"]: linefeed (ASCII 10)@nonalpha[]}
@item{ @litchar["#\\vtab"]: vertical tab (ASCII 11)@nonalpha[]}
@item{ @litchar["#\\page"]: page break (ASCII 12)@nonalpha[]}
@item{ @litchar["#\\return"]: carriage return (ASCII 13)@nonalpha[]}
@item{ @litchar["#\\space"]: space (ASCII 32)@nonalpha[]}
@item{ @litchar["#\\rubout"]: delete (ASCII 127)@nonalpha[]}
@item{@litchar["#\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}:
Unicode for the octal number specified by @kleenerange[1
3]{@nonterm{digit@sub{8}}}, as in string escapes (see
@secref["mz:parse-string"]).}
@item{@litchar["#\\x"]@kleenerange[1 2]{@nonterm{digit@sub{16}}}:
Unicode for the hexadecimal number specified by @kleenerange[1
2]{@nonterm{digit@sub{16}}}, as in string escapes (see
@secref["mz:parse-string"]).}
@item{@litchar["#\\u"]@kleenerange[1 4]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to four hexadecimal digits.}
@item{@litchar["#\\U"]@kleenerange[1 6]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to six hexadecimal digits.}
@item{@litchar["#\\"]@nonterm{c}: the character @nonterm{c}, as long
as @litchar["#\\"]@nonterm{c} and the characters following it
do not match any of the previous cases, and as long as the
character after @nonterm{c} is not
@schemelink[char-alphabetic?]{alphabetic}.}
}
@reader-examples[
"#\\newline"
"#\\n"
"#\\u3BB"
"#\\\u3BB"
]
@section[#:tag "mz:parse-keyword"]{Reading Keywords}
A @litchar{#:} starts a keyword. The parsing of a keyword after the
@litchar{#:} is the same as for a symbol, including case-folding in
case-insensitive mode, except that the part after @litchar{#:} is
never parsed as a number.
@reader-examples[
"#:Apple"
"#:1"
]
@section[#:tag "mz:parse-regexp"]{Reading Regular Expressions}
A @litchar{#rx} or @litchar{#px} starts a regular expression. The
characters immediately after @litchar{#rx} or @litchar{#px} must parse
as a string or byte string (see @secref["mz:parse-string"]). A
@litchar{#rx} prefix starts a regular expression as would be
constructed by @scheme[regexp], @litchar{#px} as
constructed by @scheme[pregexp], @litchar{#rx#} as
constructed by @scheme[byte-regexp], and @litchar{#px#} as
constructed by @scheme[byte-pregexp].
@reader-examples[
"#rx\".*\""
"#px\"[\\\\s]*\""
"#rx#\".*\""
"#px#\"[\\\\s]*\""
]
@section[#:tag "mz:parse-graph"]{Reading Graph Structure}
A @graph-defn[] tags the following datum for reference via
@graph-ref[], which allows the reader to produce a datum that
have graph structure.
For a specific @graph-tag in a single read result, each @graph-ref[]
reference is replaced by the datum read for the corresponding
@graph-defn[]; the definition @graph-defn[] also produces just the
datum after it. A @graph-defn[] definition can appear at most
once, and a @graph-defn[] definition must appear before a @graph-ref[]
reference appears.
Although a comment parsed via @litchar{#;} discards the datum
afterward, @graph-defn[] definitions in the discarded datum
still can be referenced by other parts of the reader input, as long as
both the comment and the reference are grouped together by some other
form (i.e., some recursive read); a top-level @litchar{#;} comment
neither defines nor uses graph tags for other top-level forms.
@reader-examples[
"(#1=100 #1# #1#)"
"#0=(1 . #0#)"
]
@section[#:tag "mz:parse-reader"]{Reading via an External Reader}
When the reader encounters @litchar{#reader}, then it loads an
external reader procedure and applies it to the current input stream.
The reader recursively reads the next datum after @litchar{#reader},
and passes it to the procedure that is the value of the
@scheme[current-reader-guard] @tech{parameter}; the result is used as a
module path. The module path is passed to @scheme[dynamic-require]
with either @scheme['read] or @scheme['read-syntax] (depending on
whether the reader is in @scheme[read] or @scheme[read-syntax]
mode).
The resulting procedure should accept the same arguments as
@scheme[read] or @scheme[read-syntax] in the case thar all optional
arguments are provided. The procedure is given the port whose stream
contained @litchar{#reader}, and it should produce a datum result. If
the result is a syntax object in @scheme[read] mode, then it is
converted to a datum using @scheme[syntax-object->datum]; if the
result is not a syntax object in @scheme[read-syntax] mode, then it is
converted to one using @scheme[datum->syntax-object]. See also
@secref["special-comments"] and @secref["recursive-reads"] for
information on special-comment results and recursive reads.
If the @scheme[read-accept-reader] @tech{parameter} is set to
@scheme[#f], then if the reader encounters @litchar{#reader}, the
@exnraise[exn:fail:read].
@section[#:tag "mz:readtables"]{Readtables}
The dispatch table in @secref["mz:default-readtable-dispatch"]
corresponds to the default @idefterm{readtable}.
@section[#:tag "mz:parse-honu"]{Honu Parsing}

View File

@ -1,7 +1,7 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title{PLT Scheme Reference Manual}
@title{PLT Scheme Reference}
This manual defines the core PLT Scheme language and describes its
most prominent libraries. The companion manual
@ -16,24 +16,23 @@ language.
@include-section["model.scrbl"]
@include-section["syntax-model.scrbl"]
@include-section["read.scrbl"]
@include-section["syntax.scrbl"]
@include-section["derived.scrbl"]
@include-section["data.scrbl"]
@include-section["struct.scrbl"]
@include-section["io.scrbl"]
@include-section["regexps.scrbl"]
@include-section["control.scrbl"]
@include-section["concurrency.scrbl"]
@include-section["custodians.scrbl"]
@include-section["security.scrbl"]
@include-section["io.scrbl"]
@;------------------------------------------------------------------------
@section{Platform-Specific Path Conventions}
@section{Operating System}
@subsection[#:tag "mz:unix-path"]{Unix and Mac OS X Paths}
@subsection{Platform-Specific Path Conventions}
@subsection[#:tag "mz:windows-path"]{Windows Paths}
@subsubsection[#:tag "mz:unix-path"]{Unix and Mac OS X Paths}
@subsubsection[#:tag "mz:windows-path"]{Windows Paths}
@;------------------------------------------------------------------------

View File

@ -0,0 +1,14 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "bnf.ss" "scribble")]
@require["mz.ss"]
@title[#:style 'toc]{Security}
MzScheme offers several mechanisms for managing security, each of
which relies on @tech{thread}- and @tech{continuation}-specific
@tech{parameters} (see @secref["mz:parameters"]).
@local-table-of-contents[]
@;------------------------------------------------------------------------
@include-section["custodians.scrbl"]

View File

@ -0,0 +1,377 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "bnf.ss" "scribble")]
@require["mz.ss"]
@title{Byte and String Input}
@defproc[(read-char [in input-port? (current-input-port)])
(or/c character? eof-object?)]{
Reads a single character from @scheme[in]---which may involve reading
several bytes to UTF-8-decode them into a character (see
@secref["mz:ports"]); a minimal number of bytes are read/peeked to
perform the decoding. If no bytes are available before an end-of-file,
then @scheme[eof] is returned.}
@defproc[(read-byte [in input-port? (current-input-port)])
(or/c byte? eof-object?)]{
Reads a single byte from @scheme[in]. If no bytes are available before
an end-of-file, then @scheme[eof] is returned.}
@defproc[(read-line [in input-port? (current-input-port)]
[mode (one-of 'linefeed 'return 'return-linefeed 'any 'any-one) 'linefeed])
(or/c string? eof-object?)]{
Returns a string containing the next line of bytes from @scheme[in].
Characters are read from @scheme[in] until a line separator or an
end-of-file is read. The line separator is not included in the result
string (but it is removed from the port's stream). If no characters
are read before an end-of-file is encountered, @scheme[eof] is
returned.
The @scheme[mode] argument determines the line separator(s). It
must be one of the following symbols:
@itemize{
@item{@scheme['linefeed] breaks lines on linefeed characters.}
@item{@scheme['return] breaks lines on return characters.}
@item{@scheme['return-linefeed] breaks lines on
return-linefeed combinations. If a return character is not followed
by a linefeed character, it is included in the result string;
similarly, a linefeed that is not preceded by a return is included
in the result string.}
@item{@scheme['any] breaks lines on any of a return
character, linefeed character, or return-linefeed combination. If a
return character is followed by a linefeed character, the two are
treated as a combination.}
@item{@scheme['any-one] breaks lines on either a return or
linefeed character, without recognizing return-linefeed
combinations.}
}
Return and linefeed characters are detected after the conversions that
are automatically performed when reading a file in text mode. For
example, reading a file in text mode under Windows automatically
changes return-linefeed combinations to a linefeed. Thus, when a file
is opened in text mode, @scheme['linefeed] is usually the appropriate
@scheme[read-line] mode.}
@defproc[(read-bytes-line [in input-port? (current-input-port)]
[mode (one-of 'linefeed 'return 'return-linefeed 'any 'any-one) 'linefeed])
(or/c bytes? eof-object?)]{
Like @scheme[read-line], but reads bytes and produces a byte string.}
@defproc[(read-string [amt nonnegative-exact-integer?]
[in input-port? (current-input-port)])
(or/c string? eof-object)]{
Returns a string containing the next @scheme[amt] characters from
@scheme[in].
If @scheme[amt] is @scheme[0], then the empty string is
returned. Otherwise, if fewer than @scheme[amt] characters are
available before an end-of-file is encountered, then the returned
string will contain only those characters before the end-of-file; that
is, the returned string's length will be less than @scheme[amt]. (A
temporary string of size @scheme[amt] is allocated while reading the
input, even if the size of the result is less than @scheme[amt]
characters.) If no characters are available before an end-of-file,
then @scheme[eof] is returned.
If an error occurs during reading, some characters may be lost; that
is, if @scheme[read-string] successfully reads some characters before
encountering an error, the characters are dropped.}
@defproc[(read-bytes [amt nonnegative-exact-integer?]
[in input-port? (current-input-port)])
(or/c bytes? eof-object)]{
Like @scheme[read-string], but reads bytes and produces a byte string.}
@defproc[(read-string! [str (and/c string? (not/c immutable?))]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (string-length str)])
(or/c positive-exact-integer? eof-object?)]{
Reads characters from @scheme[in] like @scheme[read-string], but puts
them into @scheme[str] starting from index @scheme[start-pos]
(inclusive) up to @scheme[end-pos] (exclusive). Like
@scheme[substring], the @exnraise[exn:fail:contract] if
@scheme[start-pos] or @scheme[end-pos] is out-of-range for
@scheme[str].
If the difference between @scheme[start-pos] and @scheme[end-pos] is
@scheme[0], then @scheme[0] is returned and @scheme[str] is not
modified. If no bytes are available before an end-of-file, then
@scheme[eof] is returned. Otherwise, the return value is the number of
characters read. If @math{m} characters are read and
@math{m<@scheme[end-pos]-@scheme[start-pos]}, then @scheme[str] is
not modified at indices @math{@scheme[start-pos]+m} though
@scheme[end-pos].}
@defproc[(read-bytes! [bstr bytes?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c positive-exact-integer? eof-object?)]{
Like @scheme[read-string!], but reads bytes, puts them into a byte
string, and returns the number of bytes read.}
@defproc[(read-bytes-avail! [bstr bytes?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c positive-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes!], but it returns without blocking after
reading immediately-available bytes, and it may return a procedure for
a ``special'' result. The @scheme[read-bytes-avail!] procedure blocks
only if no bytes (or specials) are yet available. Also unlike
@scheme[read-bytes!], @scheme[read-bytes-avail!] never drops bytes; if
@scheme[read-bytes-avail!] successfully reads some bytes and then
encounters an error, it suppresses the error (treating it roughly like
an end-of-file) and returns the read bytes. (The error will be
triggered by future reads.) If an error is encountered before any
bytes have been read, an exception is raised.
When @scheme[in] produces a special value, as described in
@secref["mz:customport"], the result is a procedure of four
arguments. The four arguments correspond to the location of the
special value within the port, as described in
@secref["mz:customport"]. If the procedure is called more than once
with valid arguments, the @exnraise[exn:fail:contract]. If
@scheme[read-bytes-avail] returns a special-producing procedure, then
it does not place characters in @scheme[bstr]. Similarly,
@scheme[read-bytes-avail] places only as many bytes into @scheme[bstr]
as are available before a special value in the port's stream.}
@defproc[(read-bytes-avail!* [bstr bytes?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c nonnegative-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes-avail!], but returns @scheme[0] immediately if
no bytes (or specials) are available for reading and the end-of-file
is not reached.}
@defproc[(read-bytes-avail!/enable-break [bstr bytes?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c positive-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes-avail!], but breaks are enabled during the
read (see also @secref["mz:breakhandler"]). If breaking is disabled
when @scheme[read-bytes-avail!/enable-break] is called, and if the
@scheme[exn:break] exception is raised as a result of the call, then
no bytes will have been read from @scheme[in].}
@defproc[(peek-string [amt nonnegative-exact-integer?]
[skip-bytes-amt nonnegative-exact-integer?]
[in input-port? (current-input-port)])
(or/c string? eof-object)]{
Similar to @scheme[read-string], except that the returned characters
are preserved in the port for future reads. (More precisely, undecoded
bytes are left for future reads.) The @scheme[skip-bytes-amt] argument
indicates a number of bytes (@italic{not} characters) in the input
stream to skip before collecting characters to return; thus, in total,
the next @scheme[skip-bytes-amt] bytes plus @scheme[amt] characters
are inspected.
For most kinds of ports, inspecting @scheme[skip-bytes-amt] bytes and
@scheme[amt] characters requires at least
@math{@scheme[skip-bytes-amt]+@scheme[amt]} bytes of memory overhead
associated with the port, at least until the bytes/characters are
read. No such overhead is required when peeking into a string port
(see @secref["mz:stringport"]), a pipe port (see
@secref["mz:pipeports"]), or a custom port with a specific peek
procedure (depending on how the peek procedure is implemented; see
@secref["mz:customport"]).
If a port produces @scheme[eof] mid-stream, peek skips beyond the
@scheme[eof] always produce @scheme[eof] until the @scheme[eof] is
read.}
@defproc[(peek-bytes [amt nonnegative-exact-integer?]
[skip-bytes-amt nonnegative-exact-integer?]
[in input-port? (current-input-port)])
(or/c bytes? eof-object)]{
Like @scheme[peek-string], but peeks bytes and produces a byte string.}
@defproc[(peek-string! [str (and/c string? (not/c immutable?))]
[skip-bytes-amt nonnegative-exact-integer?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (string-length str)])
(or/c positive-exact-integer? eof-object?)]{
Like @scheme[read-string!], but for peeking, and with a
@scheme[skip-bytes-amt] argument like @scheme[peek-string].}
@defproc[(peek-bytes! [bstr (and/c bytes? (not/c immutable?))]
[skip-bytes-amt nonnegative-exact-integer?]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c positive-exact-integer? eof-object?)]{
Like @scheme[peek-string!], but peeks bytes, puts them into a byte
string, and returns the number of bytes read.}
@defproc[(peek-bytes-avail! [bstr (and/c bytes? (not/c immutable?))]
[skip-bytes-amt nonnegative-exact-integer?]
[progress (or/c evt? false/c) #f]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c nonnegative-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes-avail!], but for peeking, and with two extra
arguments. The @scheme[skip-bytes-amt] argument is as in
@scheme[peek-bytes]. The @scheme[progress] argument must be either
@scheme[#f] or an event produced by
@scheme[port-progress-evt] for @scheme[in].
To peek, @scheme[peek-bytes-avail!] blocks until finding an
end-of-file, at least one byte (or special) past the skipped bytes, or
until a non-@scheme[#f] @scheme[progress] becomes ready. Furthermore,
if @scheme[progress] is ready before bytes are peeked, no bytes are
peeked or skipped, and @scheme[progress] may cut short the skipping
process if it becomes available during the peek attempt.
The result of @scheme[peek-bytes-avail!] is @scheme[0] only in the
case that @scheme[progress] becomes ready before bytes are peeked.}
@defproc[(peek-bytes-avail!* [bstr (and/c bytes? (not/c immutable?))]
[skip-bytes-amt nonnegative-exact-integer?]
[progress (or/c evt? false/c) #f]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c nonnegative-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes-avail!*], but for peeking, and with
@scheme[skip-bytes-amt] and @scheme[progress] arguments like
@scheme[peek-bytes-avail!]. Since this procedure never blocks, it may
return before even @scheme[skip-amt] bytes are available from the
port.}
@defproc[(peek-bytes-avail!/enable-break [bstr (and/c bytes? (not/c immutable?))]
[skip-bytes-amt nonnegative-exact-integer?]
[progress (or/c evt? false/c) #f]
[in input-port? (current-input-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c nonnegative-exact-integer? eof-object? procedure?)]{
Like @scheme[read-bytes-avail!/enable-break], but for peeking, and
with @scheme[skip-bytes-amt] and @scheme[progress] arguments like
@scheme[peek-bytes-avail!].}
@defproc[(read-char-or-special [in input-port? (current-input-port)])
(or/c character? eof-object? any/c)]{
Like @scheme[read-char], but that if the input port returns a non-byte
value (through a value-generating procedure in a custom port; see
@secref["mz:customport"] and @secref["mz:special-comments"] for
details), the non-byte value is returned.}
@defproc[(read-byte-or-special [in input-port? (current-input-port)])
(or/c byte? eof-object? any/c)]{
Like @scheme[read-char-or-special], but reads and returns a byte
instead of a character.}
@defproc[(peek-char [in input-port? (current-input-port)]
[skip-bytes-amt nonnegative-exact-integer? 0])
(or/c character? eof-object?)]{
Like @scheme[read-char], but peeks instead of reading, and skipping
@scheme[skip-bytes-amt] bytes (not characters) at the start of the
port.}
@defproc[(peek-byte [in input-port? (current-input-port)]
[skip-bytes-amt nonnegative-exact-integer? 0])
(or/c byte? eof-object?)]{
Like @scheme[peek-char], but reads and returns a byte instead of a
character.}
@defproc[(peek-char-or-special [in input-port? (current-input-port)]
[skip-bytes-amt nonnegative-exact-integer? 0])
(or/c character? eof-object? any/c)]{
Like @scheme[peek-char], but if the input port returns a non-byte
value after @scheme[skip-bytes-amt] byte positions, it is returned.}
@defproc[(peek-byte-or-special [in input-port? (current-input-port)]
[skip-bytes-amt nonnegative-exact-integer? 0]
[progress (or/c evt? false/c) #f])
(or/c character? eof-object? any/c)]{
Like @scheme[peek-char-or-special], but reads and returns a byte
instead of a character, and it supports a @scheme[progress] argument
like @scheme[peek-bytes-avail!].}
@defproc[(port-progress-evt [in input-port? (current-input-port)])
evt?]{
Returns an event that becomes ready after any subsequent read from
@scheme[in], or after @scheme[in] is closed. After the event becomes
ready, it remains ready. If progress events are unavailable for
@scheme[in] (as reported by @scheme[port-provides-progress-evts?]) the
@exnraise[exn:fail:contract].}
@defproc[(port-provides-progress-evts? [in input-port?]) boolean]{
Returns @scheme[#t] if @scheme[port-progress-evt] can return an event
for @scheme[in]. All built-in kinds of ports support progress events,
but ports created with @scheme[make-input-port] (see
@secref["mz:customport"]) may not.}
@defproc[(port-commit-peeked [amt nonnegative-exact-integer?]
[progress evt?]
[evt evt?]
[in input-port? (current-input-port)])
boolean?]{
Attempts to commit as read the first @scheme[amt] previously peeked
bytes, non-byte specials, and @scheme[eof]s from @scheme[in], or the
first @scheme[eof] or special value peeked from
@scheme[in]. (Only mid-stream @scheme[eof]s can be
committed. A @scheme[eof] when the port is exhausted does not
correspond to data in the stream.)
The read commits only if @scheme[progress] does not become ready first
(i.e., if no other process reads from @scheme[in] first), and only if
@scheme[evt] is chosen by a @scheme[sync] within
@scheme[port-commit-peeked] (in which case the event result is
ignored); the @scheme[evt] must be either a channel-put event,
channel, semaphore, semaphore-peek event, always event, or never
event. Suspending the thread that calls @scheme[port-commit-peeked]
may or may not prevent the commit from proceeding.
The result from @scheme[port-commit-peeked] is @scheme[#t] if data is
committed, and @scheme[#f] otherwise.
If no data has been peeked from @scheme[in] and @scheme[progress] is
not ready, then @exnraise[exn:fail:contract]. If fewer than
@scheme[amt] items have been peeked at the current start of
@scheme[in]'s stream, then only the peeked items are committed as
read. If @scheme[in]'s stream currently starts at an @scheme[eof] or
a non-byte special value, then only the @scheme[eof] or special value
is committed as read.
If @scheme[progress] is not a result of @scheme[port-progress-evt]
applied to @scheme[in], then @exnraise[exn:fail:contract].}

View File

@ -0,0 +1,150 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "bnf.ss" "scribble")]
@require["mz.ss"]
@title{Byte and String Output}
@defproc[(write-char [char character?][out output-port? (current-output-port)])
void?]{
Writes a single character to @scheme[out]; more precisely, the bytes
that are the UTF-8 encoding of @scheme[char] are written to
@scheme[out].}
@defproc[(write-byte [byte any/c][out output-port? (current-output-port)])
void?]{
Writes a single byte to @scheme[out].}
@defproc[(write-string [str string?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (string-length str)])
void?]{
Writes characters to @scheme[out] from @scheme[str] starting from
index @scheme[start-pos] (inclusive) up to @scheme[end-pos]
(exclusive). Like @scheme[substring], the @exnraise[exn:fail:contract]
if @scheme[start-pos] or @scheme[end-pos] is out-of-range for
@scheme[str].
The result is the number of characters written to @scheme[out], which
is always @scheme[(- end-pos start-pos)].}
@defproc[(write-bytes [bstr bytes?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
void?]{
Like @scheme[write-string], but writes bytes instead of characters.}
@defproc[(write-bytes-avail [bstr bytes?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
nonnegative-exact-integer?]{
Like @scheme[write-bytes], but returns without blocking after writing
as many bytes as it can immediately flush. It blocks only if no bytes
can be flushed immediately. The result is the number of bytes written
and flushed to @scheme[out]; if @scheme[start-pos] is the same as
@scheme[end-pos], then the result can be @scheme[0] (indicating a
successful flush of any buffered data), otherwise the result is at
least @scheme[1] but possibly less than @scheme[(- end-pos
start-pos)].
The @scheme[write-bytes-avail] procedure never drops bytes; if
@scheme[write-bytes-avail] successfully writes some bytes and then
encounters an error, it suppresses the error and returns the number of
written bytes. (The error will be triggered by future writes.) If an
error is encountered before any bytes have been written, an exception
is raised.}
@defproc[(write-bytes-avail* [bstr bytes?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
(or/c nonnegative-exact-integer? false/c)]{
Like @scheme[write-bytes-avail], but never blocks, returns @scheme[#f]
if the port contains buffered data that cannot be written immediately,
and returns @scheme[0] if the port's internal buffer (if any) is
flushed but no additional bytes can be written immediately.}
@defproc[(write-bytes-avail/enable-break [bstr bytes?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
nonnegative-exact-integer?]{
Like @scheme[write-bytes-avail], except that breaks are enabled during
the write. The procedure provides a guarantee about the interaction of
writing and breaks: if breaking is disabled when
@scheme[write-bytes-avail/enable-break] is called, and if the
@scheme[exn:break] exception is raised as a result of the call, then
no bytes will have been written to @scheme[out]. See also
@secref["mz:breakhandler"].}
@defproc[(write-special [v any/c][out output-port? (current-output-port)]) boolean?]{
Writes @scheme[v] directly to @scheme[out] if the port supports
special writes, or raises @scheme[exn:fail:contract] if the port does
not support special write. The result is always @scheme[#t],
indicating that the write succeeded.}
@defproc[(write-special-avail* [v any/c][out output-port? (current-output-port)]) boolean?]{
Like @scheme[write-special], but without blocking. If @scheme[v]
cannot be written immediately, the result is @scheme[#f] without
writing @scheme[v], otherwise the result is @scheme[#t] and @scheme[v]
is written.}
@defproc[(write-bytes-avail-evt [bstr bytes?]
[out output-port? (current-output-port)]
[start-pos nonnegative-exact-integer? 0]
[end-pos nonnegative-exact-integer? (bytes-length bstr)])
evt?]{
Similar to @scheme[write-bytes-avail], but instead of writing bytes
immediately, it returns a synchronizable event (see
@secref["mz:sync"]). The @scheme[out] must support atomic writes, as
indicated by @scheme[port-writes-atomic?].
Synchronizing on the object starts a write from @scheme[bstr], and the
event becomes ready when bytes are written (unbuffered) to the
port. If @scheme[start-pos] and @scheme[end-pos] are the same, then
the synchronization result is @scheme[0] when the port's internal
buffer (if any) is flushed, otherwise the result is a positive exact
integer. If the event is not selected in a synchronization, then no
bytes will have been written to @scheme[out].}
@defproc[(write-special-evt [v any/c][out output-port? (current-output-port)]) evt?]{
Similar to @scheme[write-special], but instead of writing the special
value immediately, it returns a synchronizable event (see
@secref["mz:sync"]). The @scheme[out] must support atomic writes, as
indicated by @scheme[port-writes-atomic?].
Synchronizing on the object starts a write of the special value, and
the event becomes ready when the value is written (unbuffered) to the
port. If the event is not selected in a synchronization, then no value
will have been written to @scheme[out].}
@defproc[(port-writes-atomic? [out output-port?]) boolean?]{
Returns @scheme[#t] if @scheme[write-bytes-avail/enable-break] can
provide an exclusive-or guarantee (break or write, but not both) for
@scheme[out], and if the port can be used with procedures like
@scheme[write-bytes-avail-evt]. Scheme's file-stream ports, pipes,
string ports, and TCP ports all support atomic writes; ports created
with @scheme[make-output-port] (see @secref["mz:customport"]) may
support atomic writes.}
@defproc[(port-writes-special? [out output-port?]) boolean?]{
Returns @scheme[#t] if procedures like @scheme[write-special] can
write arbitrary values to the port. Scheme's file-stream ports,
pipes, string ports, and TCP ports all reject special values, but
ports created with @scheme[make-output-port] (see
@secref["mz:customport"]) may support them.}

View File

@ -15,8 +15,6 @@ accessed and changed with type-specific @tech{accessor} and
@tech{predicate} procedure that answers @scheme[#t] for instances of
the structure type and @scheme[#f] for any other value.
@refalso["mz:define-struct"]{structure types via @scheme[define-struct]}
A structure type's fields are essentially unnamed, though names are
supported for error-reporting purposes. The constructor procedure
takes one value for each field of the structure type, except that some
@ -56,6 +54,9 @@ results of applying @scheme[struct->vector] to the structs are
@scheme[equal?]. (Consequently, @scheme[equal?] testing for structures
depends on the current inspector.)
@;------------------------------------------------------------------------
@include-section["define-struct.scrbl"]
@;------------------------------------------------------------------------
@section[#:tag "mz:creatingmorestructs"]{Creating Structure Types}

View File

@ -3,10 +3,10 @@
@define[cvt (schemefont "CVT")]
@title[#:tag "mz:syntax" #:style 'toc]{Core Syntactic Forms}
@title[#:tag "mz:syntax" #:style 'toc]{Syntactic Forms}
This section describes core syntax forms that apear in a fully
expanded expression, plus a few closely-related non-core forms.
This section describes the core syntax forms that apear in a fully
expanded expression, plus a many closely-related non-core forms.
@local-table-of-contents[]
@ -465,7 +465,7 @@ and in the @scheme[body]s.
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:if"]{Conditionals: @scheme[if]}
@section[#:tag "mz:if"]{Conditionals: @scheme[if], @scheme[cond], @scheme[and], and @scheme[or]}
@guideintro["guide:conditionals"]{conditionals}
@ -483,6 +483,112 @@ position with respect to the @scheme[if] form.
(if (positive? 5) 1 (error "doesn't get here"))
]}
@defform/subs[#:literals (else =>)
(cond cond-clause ...)
([cond-clause [test-expr then-expr ...+]
[else then-expr ...+]
[test-expr => proc-expr]
[test-expr]])]{
@guideintro["guide:cond"]{@scheme[cond]}
A @scheme[cond-clause] that starts with @scheme[else] must be the last
@scheme[cond-clause].
If no @scheme[cond-clause]s are present, the result is @|void-const|.
If only a @scheme[[else then-expr ...+]] is present, then the
@scheme[then-expr]s are evaluated. The results from all but the last
@scheme[then-expr] are ignored. The results of the last
@scheme[then-expr], which is in tail position with respect to the
@scheme[cond] form, provides the result for the whole @scheme[cond]
form.
Otherwise, the first @scheme[test-expr] is evaluated. If it produces
@scheme[#f], then the result is the same as a @scheme[cond] form with
the remaining @scheme[cond-clause]s, in tail position with respect to
the original @scheme[cond] form. Otherwise, evaluation depends on the
form of the @scheme[cond-clause]:
@specsubform[[test-expr then-expr ...+]]{The @scheme[then-expr]s are
evaluated in order, and the results from all but the last
@scheme[then-expr] are ignored. The results of the last
@scheme[then-expr], which is in tail position with respect to the
@scheme[cond] form, provides the result for the whole @scheme[cond]
form.}
@specsubform[#:literals (=>) [test-expr => proc-expr]]{The @scheme[proc-expr] is
evaluated, and it must produce a procedure that accepts on argument,
otherwise the @exnraise[exn:fail:contract]. The procedure is applied
to the result of @scheme[test-expr] in tail position with respect to
the @scheme[cond] expression.}
@specsubform[[test-expr]]{The result of the @scheme[test-expr] is
returned as the result of the @scheme[cond] form. The
@scheme[test-expr] is not in tail position.}
@examples[
(cond)
(cond
[else 5])
(cond
[(positive? -5) (error "doesn't get here")]
[(zero? -5) (error "doesn't get here, either")]
[(positive? 5) 'here])
(cond
[(member 2 '(1 2 3)) => (lambda (l) (map - l))])
(cond
[(member 2 '(1 2 3))])
]}
@defform[(and expr ...)]{
@guideintro["guide:and+or"]{@scheme[and]}
If no @scheme[expr]s are provided, then result is @scheme[#f].
If a single @scheme[expr] is provided, then it is in tail position, so
the results of the @scheme[and] expression are the results of the
@scheme[expr].
Otherwise, the first @scheme[expr] is evaluated. If it produces
@scheme[#f], the result of the @scheme[and] expression is
@scheme[#f]. Otherwise, the result is the same as an @scheme[and]
expression with the remaining @scheme[expr]s in tail position with
respect to the original @scheme[and] form.
@examples[
(and)
(and 1)
(and (values 1 2))
(and #f (error "doesn't get here"))
(and #t 5)
]}
@defform[(or expr ...)]{
@guideintro["guide:and+or"]{@scheme[or]}
If no @scheme[expr]s are provided, then result is @scheme[#t].
If a single @scheme[expr] is provided, then it is in tail position, so
the results of the @scheme[and] expression are the results of the
@scheme[expr].
Otherwise, the first @scheme[expr] is evaluated. If it produces a
value other than @scheme[#f], that result is the result of the
@scheme[or] expression. Otherwise, the result is the same as an
@scheme[or] expression with the remaining @scheme[expr]s in tail
position with respect to the original @scheme[or] form.
@examples[
(or)
(or 1)
(or (values 1 2))
(or 5 (error "doesn't get here"))
(or #f 5)
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:define"]{Definitions: @scheme[define] and @scheme[define-values]}
@ -600,6 +706,38 @@ in tail position only if no @scheme[body]s are present.
(printf "hi\n"))
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:when+unless"]{Guarded Evaluation: @scheme[when] and @scheme[unless]}
@guideintro["guide:when+unless"]{@scheme[when] and @scheme[unless]}
@defform[(when test-expr expr ...)]{
Evaluates the @scheme[text-expr]. If the result is any value other
than @scheme[#f], the @scheme[expr]s are evaluated, and the results
are ignored. No @scheme[expr] is in tail position with respect to the
@scheme[when] form.
@examples[
(when (positive? -5)
(display "hi"))
(when (positive? 5)
(display "hi")
(display " there"))
]}
@defform[(unless test-expr expr ...)]{
Equivalent to @scheme[(when (not test-expr) expr ...)].
@examples[
(unless (positive? 5)
(display "hi"))
(unless (positive? -5)
(display "hi")
(display " there"))
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:set!"]{Assignment: @scheme[set!] and @scheme[set!-values]}
@ -638,6 +776,8 @@ corresponding value from @scheme[expr] in the same way as for
(list a b))
]}
@;------------------------------------------------------------------------
@include-section["for.scrbl"]
@;------------------------------------------------------------------------
@section[#:tag "mz:wcm"]{Continuation Marks: @scheme[with-continuation-mark]}

View File

@ -0,0 +1,129 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "bnf.ss" "scribble")]
@require["mz.ss"]
@define[(FmtMark . s) (apply litchar "~" s)]
@title{Writing}
@defproc[(write [datum any/c][out output-port? (current-output-port)])
void?]{
Writes @scheme[datum] to @scheme[out], normally in such a way that
instances of core datatypes can be read back in. If @scheme[out] has a
handler associated to it via @scheme[port-write-handler], then the
handler is called. Otherwise, the default printer is used (in
@scheme[write] mode), as configured by various parameters.
See @secref["mz:printer"] for more information about the default
printer.}
@defproc[(display [datum any/c][out output-port? (current-output-port)])
void?]{
Displays @scheme[datum] to @scheme[out], similar to @scheme[write],
but usually in such a way that byte- and character-based datatypes are
written as raw bytes or characters. If @scheme[out] has a handler
associated to it via @scheme[port-display-handler], then the handler
is called. Otherwise, the default printer is used (in @scheme[display]
mode), as configured by various parameters.
See @secref["mz:printer"] for more information about the default
printer.}
@defproc[(print [datum any/c][out output-port? (current-output-port)])
void?]{
Writes @scheme[datum] to @scheme[out], normally the same way as
@scheme[write]. If @scheme[out] has a handler associated to it via
@scheme[port-print-handler], then the handler is called. Otherwise,
the handler specified by @scheme[global-port-print-handler] is called;
the default handler uses the default printer in @scheme[write] mode.
The rationale for providing @scheme[print] is that @scheme[display]
and @scheme[write] both have relatively standard output conventions,
and this standardization restricts the ways that an environment can
change the behavior of these procedures. No output conventions should
be assumed for @scheme[print], so that environments are free to modify
the actual output generated by @scheme[print] in any way.}
@defproc[(fprintf [out output-port?][form string?][v any/c] ...) void?]{
Prints formatted output to @scheme[out], where @scheme[form] is a string
that is printed directly, except for special formatting
escapes:
@itemize{
@item{@FmtMark{n} or @FmtMark{%} prints a newline}
@item{@FmtMark{a} or @FmtMark{A} @scheme[display]s the next argument
among the @scheme[v]s}
@item{@FmtMark{s} or @FmtMark{S} @scheme[write]s the next argument
among the @scheme[v]s}
@item{@FmtMark{v} or @FmtMark{V} @scheme[print]s the next argument
among the @scheme[v]s}
@item{@FmtMark{e} or @FmtMark{E} outputs the next argument among the
@scheme[v]s using the current error value conversion handler (see
@scheme[error-value->string-handler]) and current error printing
width} @item{@FmtMark{c} or @FmtMark{C} @scheme[write-char]s the
next argument in @scheme[v]s; if the next argument is not a
character, the @exnraise[exn:fail:contract]}
@item{@FmtMark{b} or @FmtMark{B} prints the next argument among the
@scheme[v]s in binary; if the next argument is not an exact number, the
@exnraise[exn:fail:contract]}
@item{@FmtMark{o} or @FmtMark{O} prints the next argument among the
@scheme[v]s in octal; if the next argument is not an exact number, the
@exnraise[exn:fail:contract]}
@item{@FmtMark{x} or @FmtMark{X} prints the next argument among the
@scheme[v]s in hexadecimal; if the next argument is not an exact
number, the @exnraise[exn:fail:contract]}
@item{@FmtMark{~} prints a tilde.}
@item{@FmtMark{}@nonterm{w}, where @nonterm{w} is a whitespace character,
skips characters in @scheme[form] until a non-whitespace
character is encountered or until a second end-of-line is
encountered (whichever happens first). An end-of-line is either
@scheme[#\return], @scheme[#\newline], or @scheme[#\return] followed
immediately by @scheme[#\newline] (on all platforms).}
}
The @scheme[form] string must not contain any @litchar{~} that is
not one of the above escapes, otherwise the
@exnraise[exn:fail:contract]. When the format string requires more
@scheme[v]s than are supplied, the
@exnraise[exn:fail:contract]. Similarly, when more @scheme[v]s are
supplied than are used by the format string, the
@exnraise[exn:fail:contract].
@examples[
(fprintf (current-output-port)
"~a as a string is ~s.~n"
'(3 4)
"(3 4)")
]}
@defproc[(printf [form string?][v any/c] ...) void?]{
The same as @scheme[(fprintf (current-output-port) form v ...)].}
@defproc[(format [form string?][v any/c] ...) string?]{
Formats to a string. The result is the same as
@schemeblock[
(let ([o (open-output-string)])
(fprintf o form v ...)
(get-output-string o))
]
@examples[
(format "~a as a string is ~s.~n" '(3 4) "(3 4)")
]}