diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss index 13e97d6380..fdfd02a9bc 100644 --- a/collects/scribble/manual.ss +++ b/collects/scribble/manual.ss @@ -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) diff --git a/collects/scribblings/guide/cond.scrbl b/collects/scribblings/guide/cond.scrbl index 7d37f95ef0..4b4c4de131 100644 --- a/collects/scribblings/guide/cond.scrbl +++ b/collects/scribblings/guide/cond.scrbl @@ -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 ...+] ...)] diff --git a/collects/scribblings/guide/guide-utils.ss b/collects/scribblings/guide/guide-utils.ss index 6519f12fe9..7274dbb545 100644 --- a/collects/scribblings/guide/guide-utils.ss +++ b/collects/scribblings/guide/guide-utils.ss @@ -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"))) diff --git a/collects/scribblings/reference/cont-marks.scrbl b/collects/scribblings/reference/cont-marks.scrbl index 62dca3c851..8c8374addb 100644 --- a/collects/scribblings/reference/cont-marks.scrbl +++ b/collects/scribblings/reference/cont-marks.scrbl @@ -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 diff --git a/collects/scribblings/reference/custom-ports.scrbl b/collects/scribblings/reference/custom-ports.scrbl index 635244ae74..e19b1482ac 100644 --- a/collects/scribblings/reference/custom-ports.scrbl +++ b/collects/scribblings/reference/custom-ports.scrbl @@ -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 diff --git a/collects/scribblings/reference/data.scrbl b/collects/scribblings/reference/data.scrbl index 598e66198a..622e4c77b4 100644 --- a/collects/scribblings/reference/data.scrbl +++ b/collects/scribblings/reference/data.scrbl @@ -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} diff --git a/collects/scribblings/reference/define-struct.scrbl b/collects/scribblings/reference/define-struct.scrbl index a1c6850f19..a50968cab6 100644 --- a/collects/scribblings/reference/define-struct.scrbl +++ b/collects/scribblings/reference/define-struct.scrbl @@ -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 diff --git a/collects/scribblings/reference/derived.scrbl b/collects/scribblings/reference/derived.scrbl deleted file mode 100644 index c8d77ae743..0000000000 --- a/collects/scribblings/reference/derived.scrbl +++ /dev/null @@ -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"] diff --git a/collects/scribblings/reference/exns.scrbl b/collects/scribblings/reference/exns.scrbl index 86dc22b910..b57ba41fee 100644 --- a/collects/scribblings/reference/exns.scrbl +++ b/collects/scribblings/reference/exns.scrbl @@ -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).} + +}} diff --git a/collects/scribblings/reference/io.scrbl b/collects/scribblings/reference/io.scrbl index 064eb2e852..e1a21f2844 100644 --- a/collects/scribblings/reference/io.scrbl +++ b/collects/scribblings/reference/io.scrbl @@ -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"] diff --git a/collects/scribblings/reference/model.scrbl b/collects/scribblings/reference/model.scrbl index 3402146dac..9a3909ef85 100644 --- a/collects/scribblings/reference/model.scrbl +++ b/collects/scribblings/reference/model.scrbl @@ -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 diff --git a/collects/scribblings/reference/port-line-counting.scrbl b/collects/scribblings/reference/port-line-counting.scrbl index d05d4d607b..4ba6137184 100644 --- a/collects/scribblings/reference/port-line-counting.scrbl +++ b/collects/scribblings/reference/port-line-counting.scrbl @@ -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).} - -}} diff --git a/collects/scribblings/reference/port-procs.scrbl b/collects/scribblings/reference/port-procs.scrbl index 7b55ffd6c8..990389508a 100644 --- a/collects/scribblings/reference/port-procs.scrbl +++ b/collects/scribblings/reference/port-procs.scrbl @@ -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.} diff --git a/collects/scribblings/reference/read.scrbl b/collects/scribblings/reference/read.scrbl index e285747b4d..9ad6d81610 100644 --- a/collects/scribblings/reference/read.scrbl +++ b/collects/scribblings/reference/read.scrbl @@ -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.} \ No newline at end of file diff --git a/collects/scribblings/reference/reader.scrbl b/collects/scribblings/reference/reader.scrbl new file mode 100644 index 0000000000..2d7301b32e --- /dev/null +++ b/collects/scribblings/reference/reader.scrbl @@ -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} diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl index 41ea7fab49..4a435df11e 100644 --- a/collects/scribblings/reference/reference.scrbl +++ b/collects/scribblings/reference/reference.scrbl @@ -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} @;------------------------------------------------------------------------ diff --git a/collects/scribblings/reference/security.scrbl b/collects/scribblings/reference/security.scrbl new file mode 100644 index 0000000000..cfc8f6a38d --- /dev/null +++ b/collects/scribblings/reference/security.scrbl @@ -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"] diff --git a/collects/scribblings/reference/string-input.scrbl b/collects/scribblings/reference/string-input.scrbl new file mode 100644 index 0000000000..f748a2a0c8 --- /dev/null +++ b/collects/scribblings/reference/string-input.scrbl @@ -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].} diff --git a/collects/scribblings/reference/string-output.scrbl b/collects/scribblings/reference/string-output.scrbl new file mode 100644 index 0000000000..734c0399bf --- /dev/null +++ b/collects/scribblings/reference/string-output.scrbl @@ -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.} diff --git a/collects/scribblings/reference/struct.scrbl b/collects/scribblings/reference/struct.scrbl index 295c27e745..fb4fac0098 100644 --- a/collects/scribblings/reference/struct.scrbl +++ b/collects/scribblings/reference/struct.scrbl @@ -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} diff --git a/collects/scribblings/reference/syntax.scrbl b/collects/scribblings/reference/syntax.scrbl index 572fd3e060..ca6a11b94c 100644 --- a/collects/scribblings/reference/syntax.scrbl +++ b/collects/scribblings/reference/syntax.scrbl @@ -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]} diff --git a/collects/scribblings/reference/write.scrbl b/collects/scribblings/reference/write.scrbl new file mode 100644 index 0000000000..5fe3294add --- /dev/null +++ b/collects/scribblings/reference/write.scrbl @@ -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)") +]}