change scribble to use new-lambda and new-struct, and correlate definitions and uses via lexical binding

svn: r6714
This commit is contained in:
Matthew Flatt 2007-06-22 05:59:42 +00:00
parent 38f7ef41ed
commit 7de23b6373
48 changed files with 1511 additions and 307 deletions

View File

@ -1,9 +1,8 @@
(module basic mzscheme
(module basic (lib "new-lambda.ss" "scribblings")
(require "decode.ss"
"struct.ss"
"config.ss"
(lib "kw.ss")
(lib "list.ss")
(lib "class.ss"))
@ -19,23 +18,23 @@
(content->string content)
"_"))
(define/kw (title #:key [tag #f] [style #f] #:body str)
(define (title #:tag [tag #f] #:style [style #f] . str)
(let ([content (decode-content str)])
(make-title-decl (or tag (gen-tag content)) style content)))
(define/kw (section #:key [tag #f] #:body str)
(define (section #:tag [tag #f] . str)
(let ([content (decode-content str)])
(make-part-start 0 (or tag (gen-tag content)) content)))
(define/kw (subsection #:key [tag #f] #:body str)
(define (subsection #:tag [tag #f] . str)
(let ([content (decode-content str)])
(make-part-start 1 (or tag (gen-tag content)) content)))
(define/kw (subsubsection #:key [tag #f] #:body str)
(define (subsubsection #:tag [tag #f] . str)
(let ([content (decode-content str)])
(make-part-start 2 (or tag (gen-tag content)) content)))
(define/kw (subsubsub*section #:key [tag #f] #:body str)
(define (subsubsub*section #:tag [tag #f] . str)
(let ([content (decode-content str)])
(make-paragraph (list (make-element 'bold content)))))
@ -50,7 +49,7 @@
(provide itemize item item?)
(define/kw (itemize #:body items)
(define (itemize . items)
(let ([items (filter (lambda (v) (not (whitespace? v))) items)])
(for-each (lambda (v)
(unless (an-item? v)
@ -63,7 +62,7 @@
(define-struct an-item (flow))
(define (item? x) (an-item? x))
(define/kw (item #:body str)
(define (item . str)
(make-an-item (decode-flow str)))
;; ----------------------------------------
@ -77,28 +76,28 @@
(define (hspace n)
(make-element 'hspace (list (make-string n #\space))))
(define/kw (elem #:body str)
(define (elem . str)
(make-element #f (decode-content str)))
(define/kw (aux-elem #:body s)
(define (aux-elem . s)
(make-aux-element #f (decode-content s)))
(define/kw (italic #:body str)
(define (italic . str)
(make-element 'italic (decode-content str)))
(define/kw (bold #:body str)
(define (bold . str)
(make-element 'bold (decode-content str)))
(define/kw (tt #:body str)
(define (tt . str)
(make-element 'tt (decode-content str)))
(define/kw (span-class classname #:body str)
(define (span-class classname . str)
(make-element classname (decode-content str)))
(define/kw (subscript #:body str)
(define (subscript . str)
(make-element 'subscript (decode-content str)))
(define/kw (superscript #:body str)
(define (superscript . str)
(make-element 'superscript (decode-content str)))
;; ----------------------------------------
@ -116,20 +115,20 @@
word-seq
element-seq))
(define/kw (index* word-seq content-seq #:body s)
(define (index* word-seq content-seq . s)
(let ([key (gen-target)])
(record-index word-seq
content-seq
key
(decode-content s))))
(define/kw (index word-seq #:body s)
(define (index word-seq . s)
(let ([word-seq (if (string? word-seq)
(list word-seq)
word-seq)])
(apply index* word-seq word-seq s)))
(define/kw (as-index #:body s)
(define (as-index . s)
(let ([key (gen-target)]
[content (decode-content s)])
(record-index (list (content->string content))

View File

@ -1,11 +1,11 @@
(module doclang mzscheme
(module doclang (lib "new-lambda.ss" "scribblings") ; <--- temporary
(require "struct.ss"
"decode.ss"
(lib "kw.ss"))
(require-for-syntax (lib "kerncase.ss" "syntax"))
(provide (all-from-except mzscheme #%module-begin)
(provide (all-from-except (lib "new-lambda.ss" "scribblings") #%module-begin)
(rename *module-begin #%module-begin))
;; Module wrapper ----------------------------------------

View File

@ -26,7 +26,7 @@
scribble-eval-handler)
(define current-int-namespace (make-parameter (make-namespace)))
(define current-int-namespace (make-parameter (current-namespace)))
(define scribble-eval-handler (make-parameter (lambda (c? x) (eval x))))
(define image-counter 0)
@ -108,17 +108,11 @@
#f)))))))
(define (do-eval s)
(cond
[(and (list? s)
(eq? 'code:line (car s))
(= (length s) 3)
(list? (caddr s))
(eq? 'code:comment (caaddr s)))
(do-eval (cadr s))]
[(and (list? s)
(eq? 'eval:alts (car s))
(= (length s) 3))
(do-eval (caddr s))]
(syntax-case s (code:comment eval:alts)
[(code:line v (code:comment . rest))
(do-eval #'v)]
[(eval:alts p e)
(do-eval #'e)]
[else
(let ([o (open-output-string)])
(parameterize ([current-output-port o])
@ -160,17 +154,19 @@
v2)]
[else v]))
(define (strip-comments s)
(cond
[(and (pair? s)
(pair? (car s))
(eq? (caar s) 'code:comment))
(strip-comments (cdr s))]
[(pair? s)
(cons (strip-comments (car s))
(strip-comments (cdr s)))]
[(eq? s 'code:blank) (void)]
[else s]))
(define (strip-comments stx)
(syntax-case stx (code:comment code:blank)
[((code:comment . _) . rest)
(strip-comments #'rest)]
[(a . b)
(datum->syntax-object stx
(cons (strip-comments #'a)
(strip-comments #'b))
stx
stx
stx)]
[code:blank #'(void)]
[else stx]))
(define (do-plain-eval s catching-exns?)
@ -181,7 +177,7 @@
(syntax-rules ()
[(_ e) (#%expression
(begin (parameterize ([current-command-line-arguments #()])
(do-plain-eval (quote e) #f))
(do-plain-eval (quote-syntax e) #f))
""))]))
@ -193,7 +189,7 @@
(syntax-rules ()
[(_ e) (#%expression
(parameterize ([current-command-line-arguments #()])
(show-val (car (do-plain-eval (quote e) #f)))))]))
(show-val (car (do-plain-eval (quote-syntax e) #f)))))]))
(define (eval-example-string s)
(eval (read (open-input-string s))))
@ -239,7 +235,7 @@
[(_ t schemeinput* e ...)
(interleave t
(list (schemeinput* e) ...)
(map do-eval (list (quote e) ...)))]))
(map do-eval (list (quote-syntax e) ...)))]))
(define-syntax interaction
(syntax-rules ()

View File

@ -200,6 +200,11 @@
[(at-right) '((align "right"))]
[(at-left) '((align "left"))]
[else null])
,@(let ([a (and (list? (table-style t))
(assoc 'style (table-style t)))])
(if (and a (string? (cadr a)))
`((class ,(cadr a)))
null))
,@(if (string? (table-style t))
`((class ,(table-style t)))
null))

View File

@ -1,12 +1,11 @@
(module manual mzscheme
(module manual (lib "new-lambda.ss" "scribblings")
(require "decode.ss"
"struct.ss"
"scheme.ss"
"config.ss"
"basic.ss"
(lib "string.ss")
(lib "kw.ss")
(lib "list.ss")
(lib "class.ss"))
@ -46,7 +45,10 @@
(define (to-element/id s)
(make-element "schemesymbol" (list (to-element/no-color s))))
(define (keep-s-expr ctx s v) s)
(define (keep-s-expr ctx s v)
(if (symbol? s)
(make-just-context s ctx)
s))
(define (add-sq-prop s name val)
(if (eq? name 'paren-shape)
(make-shaped-parens s val)
@ -97,41 +99,41 @@
link procedure
idefterm)
(define/kw (onscreen #:body str)
(define (onscreen . str)
(make-element 'sf (decode-content str)))
(define (menuitem menu item)
(make-element 'sf (list menu "|" item)))
(define/kw (defterm #:body str)
(define (defterm . str)
(make-element 'italic (decode-content str)))
(define/kw (idefterm #:body str)
(define (idefterm . str)
(let ([c (decode-content str)])
(make-element 'italic c)))
(define/kw (schemefont #:body str)
(define (schemefont . str)
(apply tt str))
(define/kw (schemevalfont #:body str)
(define (schemevalfont . str)
(make-element "schemevalue" (decode-content str)))
(define/kw (schemeresultfont #:body str)
(define (schemeresultfont . str)
(make-element "schemeresult" (decode-content str)))
(define/kw (schemeidfont #:body str)
(define (schemeidfont . str)
(make-element "schemesymbol" (decode-content str)))
(define/kw (schemeparenfont #:body str)
(define (schemeparenfont . str)
(make-element "schemeparen" (decode-content str)))
(define/kw (schememetafont #:body str)
(define (schememetafont . str)
(make-element "schememeta" (decode-content str)))
(define/kw (schemekeywordfont #:body str)
(define (schemekeywordfont . str)
(make-element "schemekeyword" (decode-content str)))
(define/kw (file #:body str)
(define (file . str)
(make-element 'tt (append (list "\"") (decode-content str) (list "\""))))
(define/kw (exec #:body str)
(define (exec . str)
(make-element 'tt (decode-content str)))
(define/kw (procedure #:body str)
(define (procedure . str)
(make-element "schemeresult" (append (list "#<procedure:") (decode-content str) (list ">"))))
(define/kw (link url #:body str)
(define (link url . str)
(make-element (make-target-url url) (decode-content str)))
(provide t)
(define/kw (t #:body str)
(define (t . str)
(decode-paragraph str))
(provide schememodule)
@ -151,7 +153,7 @@
;; ----------------------------------------
(provide deftech tech)
(provide deftech tech techlink)
(define (*tech make-elem style s)
(let* ([c (decode-content s)]
@ -165,12 +167,15 @@
c
(format "tech-term:~a" s))))
(define/kw (deftech #:body s)
(define (deftech . s)
(*tech make-target-element #f (list (apply defterm s))))
(define/kw (tech #:body s)
(define (tech . s)
(*tech make-link-element "techlink" s))
(define (techlink . s)
(*tech make-link-element #f s))
;; ----------------------------------------
(provide defproc defproc* defstruct defthing defform defform* defform/subs defform*/subs defform/none
@ -218,21 +223,23 @@
(define-syntax defproc
(syntax-rules ()
[(_ (id arg ...) result desc ...)
(*defproc '[(id arg ...)]
(*defproc (list (quote-syntax id))
'[(id arg ...)]
(list (list (lambda () (arg-contract arg)) ...))
(list (lambda () (schemeblock0 result)))
(lambda () (list desc ...)))]))
(define-syntax defproc*
(syntax-rules ()
[(_ [[(id arg ...) result] ...] desc ...)
(*defproc '[(id arg ...) ...]
(*defproc (list (quote-syntax id) ...)
'[(id arg ...) ...]
(list (list (lambda () (arg-contract arg)) ...) ...)
(list (lambda () (schemeblock0 result)) ...)
(lambda () (list desc ...)))]))
(define-syntax defstruct
(syntax-rules ()
[(_ name fields desc ...)
(*defstruct 'name 'fields (lambda () (list desc ...)))]))
(*defstruct (quote-syntax name) 'name 'fields (lambda () (list desc ...)))]))
(define-syntax (defform*/subs stx)
(syntax-case stx ()
[(_ #:literals (lit ...) [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)
@ -245,8 +252,11 @@
'(unsyntax x)
#'name)
#'rest)
#'spec)])])
#'(*defforms #t '(lit ...)
#'spec)])]
[spec-id
(syntax-case #'spec ()
[(name . rest) #'name])])
#'(*defforms (quote-syntax spec-id) '(lit ...)
'(spec spec1 ...)
(list (lambda (x) (schemeblock0 new-spec))
(lambda (ignored) (schemeblock0 spec1)) ...)
@ -260,6 +270,7 @@
#'(fm #:literals () [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)]))
(define-syntax (defform* stx)
(syntax-case stx ()
[(_ #:literals lits [spec ...] desc ...) #'(defform*/subs #:literals lits [spec ...] () desc ...)]
[(_ [spec ...] desc ...) #'(defform*/subs [spec ...] () desc ...)]))
(define-syntax (defform stx)
(syntax-case stx ()
@ -312,7 +323,7 @@
(define-syntax defthing
(syntax-rules ()
[(_ id result desc ...)
(*defthing 'id 'result (lambda () (list desc ...)))]))
(*defthing (quote-syntax id) 'id 'result (lambda () (list desc ...)))]))
(define-syntax schemegrammar
(syntax-rules ()
[(_ #:literals (lit ...) id clause ...) (*schemegrammar '(lit ...)
@ -342,7 +353,7 @@
(list (make-table style content))))
(list (make-table style content))))
(define (*defproc prototypes arg-contractss result-contracts content-thunk)
(define (*defproc stx-ids prototypes arg-contractss result-contracts content-thunk)
(let ([spacer (hspace 1)]
[has-optional? (lambda (arg)
(and (pair? arg)
@ -378,7 +389,7 @@
(apply
append
(map
(lambda (prototype arg-contracts result-contract first?)
(lambda (stx-id prototype arg-contracts result-contract first?)
(append
(list
(list (make-flow
@ -403,7 +414,7 @@
(make-target-element
#f
(list (to-element (car prototype)))
(register-scheme-definition (car prototype)))
(register-scheme-definition stx-id))
(to-element (car prototype))))
(map arg->elem required)
(if (null? optional)
@ -449,25 +460,29 @@
[else null]))
(cdr prototype)
arg-contracts))))
stx-ids
prototypes
arg-contractss
result-contracts
(cons #t (map (lambda (x) #f) (cdr prototypes))))))
(content-thunk))))))
(define (make-target-element* content wrappers)
(define (make-target-element* stx-id content wrappers)
(if (null? wrappers)
content
(make-target-element*
stx-id
(make-target-element
#f
(list content)
(register-scheme-definition (string->symbol
(apply string-append
(map symbol->string (car wrappers))))))
(register-scheme-definition
(datum->syntax-object stx-id
(string->symbol
(apply string-append
(map symbol->string (car wrappers)))))))
(cdr wrappers))))
(define (*defstruct name fields content-thunk)
(define (*defstruct stx-id name fields content-thunk)
(define spacer (hspace 1))
(make-splice
(cons
@ -481,6 +496,7 @@
(to-element
`(,(schemeparenfont "struct")
,(make-target-element*
stx-id
(to-element name)
(let ([name (if (pair? name)
(car name)
@ -515,7 +531,7 @@
fields)))
(content-thunk))))
(define (*defthing name result-contract content-thunk)
(define (*defthing stx-id name result-contract content-thunk)
(define spacer (hspace 1))
(make-splice
(cons
@ -528,19 +544,19 @@
(list (make-target-element
#f
(list (to-element name))
(register-scheme-definition name))
(register-scheme-definition stx-id))
spacer ":" spacer
(to-element result-contract))))))))
(content-thunk))))
(define (meta-symbol? s) (memq s '(... ...+ ?)))
(define (*defforms kw? lits forms form-procs subs sub-procs content-thunk)
(define (*defforms kw-id lits forms form-procs subs sub-procs content-thunk)
(parameterize ([current-variable-list
(apply
append
(map (lambda (form)
(let loop ([form (cons (if kw? (cdr form) form)
(let loop ([form (cons (if kw-id (cdr form) form)
subs)])
(cond
[(symbol? form) (if (or (meta-symbol? form)
@ -568,22 +584,25 @@
(to-element
`(,x
. ,(cdr form)))))))
(and kw?
(and kw-id
(eq? form (car forms))
(make-target-element
#f
(list (to-element (car form)))
(register-scheme-form-definition (car form)))))))))
(list (to-element (make-just-context (car form) kw-id)))
(register-scheme-form-definition kw-id))))))))
forms form-procs)
(apply
append
(map (lambda (sub)
(list (list (make-flow (list (make-paragraph (list (tt 'nbsp))))))
(list (make-flow (list (apply *schemerawgrammar
(map (lambda (f) (f)) sub)))))))
sub-procs))))
(if (null? sub-procs)
null
(list (list (make-flow (list (make-paragraph (list (tt 'nbsp))))))
(list (make-flow (list (let ([l (map (lambda (sub)
(map (lambda (f) (f)) sub))
sub-procs)])
(*schemerawgrammars
"specgrammar"
(map car l)
(map cdr l))))))))))
(content-thunk)))))
(define (*specsubform form has-kw? lits form-thunk subs sub-procs content-thunk)
(parameterize ([current-variable-list
(append (let loop ([form (cons (if has-kw? (cdr form) form)
@ -610,41 +629,47 @@
(if form-thunk
(form-thunk)
(make-paragraph (list (to-element form)))))))
(apply
append
(map (lambda (sub)
(list (list (make-flow (list (make-paragraph (list (tt 'nbsp))))))
(list (make-flow (list (apply *schemerawgrammar
(map (lambda (f) (f)) sub)))))))
sub-procs))))
(if (null? sub-procs)
null
(list (list (make-flow (list (make-paragraph (list (tt 'nbsp))))))
(list (make-flow (list (let ([l (map (lambda (sub)
(map (lambda (f) (f)) sub))
sub-procs)])
(*schemerawgrammars
"specgrammar"
(map car l)
(map cdr l))))))))))
(flow-paragraphs (decode-flow (content-thunk)))))))
(define (*schemerawgrammars nonterms clauseses)
(define (*schemerawgrammars style nonterms clauseses)
(make-table
'((valignment baseline baseline baseline baseline baseline)
(alignment right left center left left))
`((valignment baseline baseline baseline baseline baseline)
(alignment right left center left left)
(style ,style))
(let ([empty-line (make-flow (list (make-paragraph (list (tt 'nbsp)))))]
[to-flow (lambda (i) (make-flow (list (make-paragraph (list i)))))])
(apply append
(map
(lambda (nonterm clauses)
(cons
(list (to-flow nonterm)
empty-line
(to-flow "=")
empty-line
(make-flow (list (car clauses))))
(map (lambda (clause)
(list empty-line
empty-line
(to-flow "|")
empty-line
(make-flow (list clause))))
(cdr clauses))))
nonterms clauseses)))))
(cdr
(apply append
(map
(lambda (nonterm clauses)
(list*
(list empty-line empty-line empty-line empty-line empty-line)
(list (to-flow nonterm)
empty-line
(to-flow "=")
empty-line
(make-flow (list (car clauses))))
(map (lambda (clause)
(list empty-line
empty-line
(to-flow "|")
empty-line
(make-flow (list clause))))
(cdr clauses))))
nonterms clauseses))))))
(define (*schemerawgrammar nonterm clause1 . clauses)
(*schemerawgrammars (list nonterm) (list (cons clause1 clauses))))
(define (*schemerawgrammar style nonterm clause1 . clauses)
(*schemerawgrammars style (list nonterm) (list (cons clause1 clauses))))
(define (*schemegrammar lits s-expr clauseses-thunk)
(parameterize ([current-variable-list
@ -657,7 +682,7 @@
(loop (cdr form)))]
[else null]))])
(let ([l (clauseses-thunk)])
(*schemerawgrammars (map car l) (map cdr l)))))
(*schemerawgrammars #f (map car l) (map cdr l)))))
(define (*var id)
(to-element (*var-sym id)))
@ -668,26 +693,26 @@
;; ----------------------------------------
(provide centerline)
(define/kw (centerline #:body s)
(define (centerline . s)
(make-table 'centered (list (list (make-flow (list (decode-paragraph s)))))))
(provide commandline)
(define/kw (commandline #:body s)
(define (commandline . s)
(make-paragraph (list (hspace 2) (apply tt s))))
(define (secref s)
(make-link-element #f null `(part ,s)))
(define/kw (seclink tag #:body s)
(define (seclink tag . s)
(make-link-element #f (decode-content s) `(part ,tag)))
(define/kw (*schemelink id #:body s)
(make-link-element #f (decode-content s) (register-scheme-definition id)))
(define (*schemelink stx-id id . s)
(make-link-element #f (decode-content s) (register-scheme-definition stx-id)))
(define-syntax schemelink
(syntax-rules ()
[(_ id . content) (*schemelink 'id . content)]))
[(_ id . content) (*schemelink (quote-syntax id) 'id . content)]))
(provide secref seclink schemelink)
(define/kw (pidefterm #:body s)
(define (pidefterm . s)
(let ([c (apply defterm s)])
(index (string-append (content->string (element-content c)) "s")
c)))
@ -707,7 +732,7 @@
;; ----------------------------------------
(provide math)
(define/kw (math #:body s)
(define (math . s)
(let ([c (decode-content s)])
(make-element #f (apply append
(map (lambda (i)
@ -727,7 +752,7 @@
(provide cite)
(define/kw (cite #:key key title author location date)
(define (cite #:key key #:title title #:author author #:location location #:date date)
"[...]"
#;
(make-bibliography-element

View File

@ -2,7 +2,8 @@
(require "struct.ss"
"basic.ss"
(lib "class.ss")
(lib "for.ss"))
(lib "for.ss")
(lib "modcollapse.ss" "syntax"))
(provide define-code
to-element
@ -17,7 +18,8 @@
current-variable-list
current-meta-list
(struct shaped-parens (val shape)))
(struct shaped-parens (val shape))
(struct just-context (val ctx)))
(define no-color "schemeplain")
(define reader-color "schemeplain")
@ -32,13 +34,12 @@
(define current-keyword-list
;; This is temporary, until the MzScheme manual is filled in...
(make-parameter '(require
(make-parameter null #;'(require
provide
new send else => and or
define-syntax syntax-rules define-struct
quote quasiquote unquote unquote-splicing
syntax quasisyntax unsyntax unsyntax-splicing
set! set!-values)))
quasiquote unquote unquote-splicing
syntax quasisyntax unsyntax unsyntax-splicing)))
(define current-variable-list
(make-parameter null))
(define current-meta-list
@ -353,8 +354,8 @@
(not (or it? is-var?)))
(make-delayed-element
(lambda (renderer sec ht)
(let* ([vtag (register-scheme-definition (syntax-e c))]
[stag (register-scheme-form-definition (syntax-e c))]
(let* ([vtag (register-scheme-definition c)]
[stag (register-scheme-form-definition c)]
[vd (hash-table-get ht vtag #f)]
[sd (hash-table-get ht stag #f)])
(list
@ -431,7 +432,7 @@
(cond
[(syntax? v)
(let ([mk `(,#'d->s
#f
(quote-syntax ,v)
,(syntax-case v (uncode)
[(uncode e) #'e]
[else (stx->loc-s-expr (syntax-e v))])
@ -463,11 +464,22 @@
[(_ code typeset-code) #'(define-code code typeset-code unsyntax)]))
(define (register-scheme-definition sym)
(format "definition:~s" sym))
(define (register-scheme-definition stx)
(unless (identifier? stx)
(error 'register-scheme-definition "not an identifier: ~e" (syntax-object->datum stx)))
(format "definition:~s"
(let ([b (identifier-binding stx)])
(cond
[(not b) (format "top:~a" (syntax-e stx))]
[(eq? b 'lexical) (format "lexical:~a" (syntax-e stx))]
[else (format "module:~a:~a"
(if (module-path-index? (car b))
(collapse-module-path-index (car b) '(lib "ack.ss" "scribble"))
(car b))
(cadr b))]))))
(define (register-scheme-form-definition sym)
(format "formdefinition:~s" sym))
(define (register-scheme-form-definition stx)
(format "form~s" (register-scheme-definition stx)))
(define syntax-ize-hook (make-parameter (lambda (v col) #f)))
@ -495,6 +507,7 @@
l))))
(define-struct shaped-parens (val shape))
(define-struct just-context (val ctx))
(define (syntax-ize v col)
(cond
@ -504,6 +517,13 @@
(syntax-property (syntax-ize (shaped-parens-val v) col)
'paren-shape
(shaped-parens-shape v))]
[(just-context? v)
(let ([s (syntax-ize (just-context-val v) col)])
(datum->syntax-object (just-context-ctx v)
(syntax-e s)
s
s
(just-context-ctx v)))]
[(and (list? v)
(pair? v)
(memq (car v) '(quote unquote unquote-splicing)))

View File

@ -184,6 +184,10 @@
background-color: #ddddff;
}
.specgrammar {
float: right;
}
.hspace {
font-family: Courier; font-size: 80%;
}

View File

@ -0,0 +1,400 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require[(lib "class.ss")]
@require["guide-utils.ss"]
@title[#:tag "classes"]{Classes and Objects}
A @scheme[class] expression denotes a first-class value,
just like a @scheme[lambda] expression:
@specform[(class superclass-expr decl-or-expr ...)]
The @scheme[_superclass-expr] determines the superclass for the new
class. Each @scheme[_decl-or-expr] is either a declaration related to
methods, fields, and intialization arguments, or it is an expression
that is evaluated each time that the class is instantiated. In other
words, instead of a method-like constructor, a class has
initialization expressions interleaved with field and method
declarations.
By convention, class names end with @schemeidfont{%}. The built-in root class is
@scheme[object%]. The following expression creates a class with
public methods @scheme[get-size], @scheme[grow], and @scheme[eat]:
@schemeblock[
(class object%
(init size) (code:comment #,(t "initialization argument"))
(define current-size size) (code:comment #,(t "field"))
(super-new) (code:comment #,(t "superclass initialization"))
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size))))
]
@interaction-eval[
(define fish%
(class object%
(init size)
(define current-size size)
(super-new)
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))))]
The @scheme[size] initialization argument must be supplied via a named
argument when instantiating the class through the @scheme[new] form:
@schemeblock[
(new (class object% (init size) ...) [size 10])
]
Of course, we can also name the class and its instance:
@schemeblock[
(define fish% (class object% (init size) ...))
(define charlie (new fish% [size 10]))
]
@interaction-eval[(define charlie (new fish% [size 10]))]
In the definition of @scheme[fish%], @scheme[current-size] is a
private field that starts out with the value of the @scheme[size]
initialization argument. Initialization arguments like @scheme[size]
are available only during class instantiation, so they cannot be
referenced directly from a method. The @scheme[current-size] field, in
contrast, is available to methods.
The @scheme[(super-new)] expression in @scheme[fish%] invokes the
initialization of the superclass. In this case, the superclass is
@scheme[object%], which takes no initialization arguments and performs
no work; @scheme[super-new] must be used, anyway, because a class must
always invoke its superclass's initialization.
Initialization arguments, field declarations, and expressions such as
@scheme[(super-new)] can appear in any order within a @scheme[class],
and they can be interleaved with method declarations. The relative
order of expressions in the class determines the order of evaluation
during instantiation. For example, if a field's initial value requires
calling a method that works only after superclass initialization, then
the field declaration is placed after the @scheme[super-new]
call. Ordering field and initialization declarations in this way helps
avoid imperative assignment. The relative order of method declarations
makes no difference for evaluation, because methods are fully defined
before a class is instantiated.
@section[#:tag "guide:methods"]{Methods}
Each of the three @scheme[define/public] declarations in
@scheme[fish%] introduces a new method. The declaration uses the same
syntax as a Scheme function, but a method is not accessible as an
independent function. A call to the @scheme[grow] method of a
@scheme[fish%] object requires the @scheme[send] form:
@interaction[
(send charlie grow 6)
(send charlie get-size)
]
Within @scheme[fish%], self methods can be called like functions,
because the method names are in scope. For example, the @scheme[eat]
method within @scheme[fish%] directly invokes the @scheme[grow]
method. Within a class, attempting to use a method name in any way
other than a method call results in a syntax error.
In some cases, a class must call methods that are supplied by the superclass
but not overridden. In that case, the class can use @scheme[send]
with @scheme[this] to access the method:
@def+int[
(define hungry-fish% (class fish% (super-new)
(define/public (eat-more fish1 fish2)
(send this eat fish1)
(send this eat fish2))))
]
Alternately, the class can declare the existence of a method using @scheme[inherit],
which brings the method name into scope for a direct call:
@def+int[
(define hungry-fish% (class fish% (super-new)
(inherit eat)
(define/public (eat-more fish1 fish2)
(eat fish1) (eat fish2))))
]
With the @scheme[inherit] declaration, if @scheme[fish%] had not
provided an @scheme[eat] method, an error would be signaled in the
evaluation of the @scheme[class] form for @scheme[hungry-fish%]. In
contrast, with @scheme[(send this ...)], an error would not be
signaled until the @scheme[eat-more] method is called and the
@scheme[send] form is evaluated. For this reason, @scheme[inherit] is
preferred.
Another drawback of @scheme[send] is that it is less efficient than
@scheme[inherit]. Invocation of a method via @scheme[send] involves
finding a method in the target object's class at run time, making
@scheme[send] comparable to an interface-based method call in Java. In
contrast, @scheme[inherit]-based method invocations use an offset
within the class's method table that is computed when the class is
created.
To achieve performance similar to @scheme[inherit]-based method calls when
invoking a method from outside the method's class, the programmer must use the
@scheme[generic] form, which produces a class- and method-specific
@defterm{generic method} to be invoked with @scheme[send-generic]:
@def+int[
(define get-fish-size (generic fish% get-size))
(send-generic charlie get-fish-size)
(send-generic (new hungry-fish% [size 32]) get-fish-size)
(send-generic (new object%) get-fish-size)
]
Roughly speaking, the form translates the class and the external
method name to a location in the class's method table. As illustrated
by the last example, sending through a generic method checks that its
argument is an instance of the generic's class.
Whether a method is called directly within a @scheme[class],
through a generic method,
or through @scheme[send], method overriding works in the usual way:
@defs+int[
[
(define picky-fish% (class fish% (super-new)
(define/override (grow amt)
;; Doesn't eat all of its food
(super grow (* 3/4 amt)))))
(define daisy (new picky-fish% [size 20]))
]
(send daisy eat charlie)
(send daisy get-size)
]
The @scheme[grow] method in @scheme[picky-fish%] is declared with
@scheme[define/override] instead of @scheme[define/public], because
@scheme[grow] is meant as an overriding declaration. If @scheme[grow]
had been declared with @scheme[define/public], an error would have
been signaled when evaluating the @scheme[class] expression, because
@scheme[fish%] already supplies @scheme[grow].
Using @scheme[define/override] also allows the invocation of the
overridden method via a @scheme[super] call. For example, the
@scheme[grow] implementation in @scheme[picky-fish%] uses
@scheme[super] to delegate to the superclass implementation.
@section[#:tag "guide:initargs"]{Initialization Arguments}
Since @scheme[picky-fish%] declares no initialization arguments, any
initialization values supplied in @scheme[(new picky-fish% ...)] are
propagated to the superclass initialization, i.e., to @scheme[fish%].
A subclass can supply additional initialization arguments for its
superclass in a @scheme[super-new] call, and such initialization
arguments take precedence over arguments supplied to @scheme[new]. For
example, the following @scheme[size-10-fish%] class always generates
fish of size 10:
@def+int[
(define size-10-fish% (class fish% (super-new [size 10])))
(send (new size-10-fish%) get-size)
]
In the case of @scheme[size-10-fish%], supplying a @scheme[size]
initialization argument with @scheme[new] would result in an
initialization error; because the @scheme[size] in @scheme[super-new]
takes precedence, a @scheme[size] supplied to @scheme[new] would have
no target declaration.
An initialization argument is optional if the @scheme[class] form
declares a default value. For example, the following @scheme[default-10-fish%]
class accepts a @scheme[size] initialization argument, but its value defaults to
10 if no value is supplied on instantiation:
@def+int[
(define default-10-fish% (class fish%
(init [size 10])
(super-new [size size])))
(new default-10-fish%)
(new default-10-fish% [size 20])
]
In this example, the @scheme[super-new] call propagates its own
@scheme[size] value as the @scheme[size] initialization argument to
the superclass.
@section[#:tag "guide:intnames"]{Internal and External Names}
The two uses of @scheme[size] in @scheme[default-10-fish%] expose the
double life of class-member identifiers. When @scheme[size] is the
first identifier of a bracketed pair in @scheme[new] or
@scheme[super-new], @scheme[size] is an @defterm{external name} that
is symbolically matched to an initialization argument in a class. When
@scheme[size] appears as an expression within
@scheme[default-10-fish%], @scheme[size] is an \defterm{internal name}
that is lexically scoped. Similarly, a call to an inherited
@scheme[eat] method uses @scheme[eat] as an internal name, whereas a
@scheme[send] of @scheme[eat] uses @scheme[eat] as an external name.
The full syntax of the @scheme[class] form allows a programmer to
specify distinct internal and external names for a class member. Since
internal names are local, they can be renamed to avoid shadowing or
conflicts. Such renaming is not frequently necessary, but workarounds
in the absence of renaming can be especially cumbersome.
@section{Interfaces}
Interfaces are useful for checking that an object or a class
implements a set of methods with a particular (implied) behavior.
This use of interfaces is helpful even without a static type system
(which is the main reason that Java has interfaces).
An interface in PLT Scheme is created using the @scheme[interface]
form, which merely declares the method names required to implement the
interface. An interface can extend other interfaces, which means that
implementations of the interface automatically implement the extended
interfaces.
@specform[(interface (superinterface-expr ...) id ...)]
To declare that a class implements an interface, the
@scheme[class*] form must be used instead of @scheme[class]:
@specform[(class* superclass-expr (interface-expr ...) decl-or-expr ...)]
For example, instead of forcing all fish classes to be derived from
@scheme[fish%], we can define @scheme[fish-interface] and change the
@scheme[fish%] class to declare that it implements
@scheme[fish-interface]:
@schemeblock[
(define fish-interface (interface () get-size grow eat))
(define fish% (class* object% (fish-interface) ...))
]
If the definition of @scheme[fish%] does not include
@scheme[get-size], @scheme[grow], and @scheme[eat] methods, then an
error is signaled in the evaluation of the @scheme[class*] form,
because implementing the @scheme[fish-interface] interface requires
those methods.
The @scheme[is-a?] predicate accepts either a class or interface as
its first argument and an object as its second argument. When given a
class, @scheme[is-a?] checks whether the object is an instance of that
class or a derived class. When given an interface, @scheme[is-a?]
checks whether the object's class implements the interface. In
addition, the @scheme[implementation?] predicate checks whether a
given class implements a given interface.
@section[#:tag "guide:inner"]{Final, Augment, and Inner}
As in Java, a method in a @scheme[class] form can be specified as
@defterm{final}, which means that a subclass cannot override the
method. A final method is declared using @scheme[public-final] or
@scheme[override-final], depending on whether the declaration is for a
new method or an overriding implementation.
Between the extremes of allowing arbitrary overriding and disallowing
overriding entirely, the {class} system also supports Beta-style
@defterm{augmentable} methods~\cite{beta}. A method
declared with @scheme[pubment] is like @scheme[public], but the method
cannot be overridden in subclasses; it can be augmented only. A
@scheme[pubment] method must explicitly invoke an augmentation (if any)
using @scheme[inner]; a subclass augments the method using
@scheme[augment], instead of @scheme[override].
In general, a method can switch between augment and override modes in
a class derivation. The @scheme[augride] method specification
indicates an augmentation to a method where the augmentation is itself
overrideable in subclasses (though the superclass's implementation
cannot be overridden). Similarly, @scheme[overment] overrides a method
and makes the overriding implementation augmentable. Our earlier
work~\cite{Super+Inner} motivates and explains these extensions and
their interleaving.
@section[#:tag "guide:extnames"]{Controlling the Scope of External Names}
As noted in @secref["guide:intnames"], class members have both
internal and external names. A member definition binds an internal
name locally, and this binding can be locally renamed. External
names, in contrast, have global scope by default, and a member
definition does not bind an external name. Instead, a member
definition refers to an existing binding for an external name, where
the member name is bound to a @defterm{member key}; a class ultimately
maps member keys to methods, fields, and initialization arguments.
Recall the @scheme[hungry-fish%] @scheme[class] expression:
@schemeblock[
(define hungry-fish% (class fish% ...
(inherit eat)
(define/public (eat-more fish1 fish2)
(eat fish1) (eat fish2))))
]
During its evaluation, the @scheme[hungry-fish%] and @scheme[fish%]
classes refer to the same global binding of @scheme[eat]. At run
time, calls to @scheme[eat] in @scheme[hungry-fish%] are matched with
the @scheme[eat] method in @scheme[fish%] through the shared method
key that is bound to @scheme[eat].
The default binding for an external name is global, but a
programmer can introduce an external-name binding with the
@scheme[define-member-name] form.
@specform[(define-member-name id member-key-expr)]
In particular, by using @scheme[(generate-member-key)] as the
@scheme[member-key-expr], an external name can be localized for a
particular scope, because the generated member key is inaccessible
outside the scope. In other words, @scheme[define-member-name] gives
an external name a kind of package-private scope, but generalized from
packages to arbitrary binding scopes in Scheme.
For example, the following @scheme[fish%] and @scheme[pond%] classes cooperate
via a @scheme[get-depth] method that is only accessible to the
cooperating classes:
@schemeblock[
(define-values (fish% pond%) (code:comment #,(t "two mutually recursive classes"))
(let () ; create a local definition scope
(define-member-name get-depth (generate-member-key))
(define fish%
(class ... (define my-depth ...)
(define my-pond ...)
(define/public (dive amt)
(set! my-depth
(min (+ my-depth amt)
(send my-pond get-depth))))))
(define pond%
(class ... (define current-depth ...)
(define/public (get-depth) current-depth)))
(values fish% pond%)))
]
External names are in a namespace that separates them from other Scheme
names. This separate namespace is implicitly used for the method name in
@scheme[send], for initialization-argument names in @scheme[new], or for
the external name in a member definition. The special
@scheme[member-name-key] provides access to the binding of an external name
in an arbitrary expression position: @scheme[(member-name-key id)] form
produces the member-key binding of @scheme[id] in the current scope.
A member-key value is primarily used on with a
@scheme[define-member-name] form. Normally, then,
@scheme[(member-name-key id)] captures the method key of @scheme[id]
so that it can be communicated to a use of @scheme[define-member-name]
in a different scope. This capability turns out to be useful for
generalizing mixins (see \SecRef{sec:parammixins}).

View File

@ -133,8 +133,8 @@ To make a structure type @defterm{transparent}, use the
field-name sequence:
@def+int[
'(define-struct posn (x y)
#:inspector #f)
(define-struct posn (x y)
#:inspector #f)
(make-posn 1 2)
]

View File

@ -2,8 +2,7 @@
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "string.ss"))]
@require[(lib "string.ss")]
@title{Definitions: @scheme[define]}

View File

@ -2,8 +2,7 @@
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "for.ss"))]
@require[(lib "for.ss")]
@title[#:tag "guide:for"]{Iterations and Comprehensions}

View File

@ -1,13 +1,10 @@
(module guide-utils mzscheme
(module guide-utils (lib "new-lambda.ss" "scribblings")
(require (lib "manual.ss" "scribble")
(lib "struct.ss" "scribble")
(lib "decode.ss" "scribble")
(lib "kw.ss")
(lib "eval.ss" "scribble"))
(interaction-eval (require (lib "new-lambda.ss" "scribblings")))
(provide Quick MzScheme HtDP
tool
refdetails
@ -26,7 +23,7 @@
(define (tool name . desc)
(apply item (bold name) ", " desc))
(define/kw (refdetails* tag what #:body s)
(define (refdetails* tag what . s)
(apply margin-note
(decode-content (append (list "For " what " on ")
s
@ -34,10 +31,10 @@
(refsecref tag)
".")))))
(define/kw (refdetails tag #:body s)
(define (refdetails tag . s)
(apply refdetails* tag "more" s))
(define/kw (refdetails/gory tag #:body s)
(define (refdetails/gory tag . s)
(apply refdetails* tag "gory details" s))
(define (refsecref s)

View File

@ -38,7 +38,7 @@ describes the acceptable arguments and the result of the procedure
using @idefterm{contracts}.
@; ----------------------------------------------------------------------
@section[#:tag "classes"]{Classes and Objects}
@include-section["class.scrbl"]
@; ----------------------------------------------------------------------

View File

@ -3,8 +3,6 @@
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "file.ss"))]
@title{Local Binding}
Although internal @scheme[define]s can be used for local binding,

View File

@ -3,9 +3,9 @@
@require[(lib "eval.ss" "scribble")]
@require[(lib "bnf.ss" "scribble")]
@require["guide-utils.ss"]
@require[(lib "list.ss")]
@require[(lib "for.ss")]
@interaction-eval[(require (lib "list.ss"))]
@interaction-eval[(require (lib "for.ss"))]
@define[step @elem{=}]
@title{Lists, Iteration, and Recursion}
@ -212,12 +212,12 @@ argument @scheme[len]:
@schemeblock[
(define (my-length lst)
(code:comment #, @elem{local function @scheme[iter]:})
(code:comment #, @t{local function @scheme[iter]:})
(define (iter lst len)
(cond
[(empty? lst) len]
[else (iter (rest lst) (+ len 1))]))
(code:comment #, @elem{body of @scheme[my-length] calls @scheme[iter]:})
(code:comment #, @t{body of @scheme[my-length] calls @scheme[iter]:})
(iter lst 0))
]

View File

@ -2,9 +2,8 @@
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "list.ss"))]
@interaction-eval[(define mutable-cons cons)]
@require[(lib "list.ss")]
@define[mutable-cons cons]
@title{Pairs and Lists}

View File

@ -2,8 +2,7 @@
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "list.ss"))]
@require[(lib "list.ss")]
@title{Pairs, Lists, and Scheme Syntax}

View File

@ -1,15 +1,18 @@
(module new-lambda mzscheme
(require-for-syntax (lib "name.ss" "syntax")
(lib "define.ss" "syntax"))
(require "new-struct.ss")
(provide (all-from-except mzscheme #%datum lambda define #%app)
(provide (all-from-except mzscheme #%datum lambda define #%app define-struct)
(rename new-datum #%datum)
(rename new-lambda lambda)
(rename new-define define)
(rename new-app #%app)
(rename *make-keyword-procedure make-keyword-procedure)
keyword-apply
procedure-keywords)
procedure-keywords
(rename define-struct* define-struct)
struct-field-index)
;; ----------------------------------------
@ -366,7 +369,7 @@
(make-optional-keyword-procedure
with-kws
null
'(kw ...)
'kws
no-kws))))]
[else
;; just the keywords part dispatches to core,

View File

@ -0,0 +1,413 @@
;; Based on
;; (planet "struct.ss" ("ryanc" "macros.plt" 1 0)))
;; though, strangely and embarassingly, Matthew didn't know that until
;; after he had mostly re-implemented it.
(module new-struct mzscheme
(require (lib "stxparam.ss"))
(provide define-struct*
struct-field-index)
(define-syntax-parameter struct-field-index
(lambda (stx)
(raise-syntax-error #f "allowed only within a structure type definition" stx)))
(define (check-struct-type name what)
(when what
(unless (struct-type? what)
(raise-type-error name "struct-type or #f" what)))
what)
(define (check-inspector name what)
(when what
(unless (inspector? what)
(raise-type-error name "inspector or #f" what)))
what)
(define-syntax (define-struct* stx)
(define make-field list)
(define field-id car)
(define field-default-value cadr)
(define field-auto? caddr)
(define field-immutable? cadddr)
(define (struct-declaration-info? x)
(define (identifier/#f? x)
(or (not x)
(identifier? x)))
(define (id/#f-list? id? x)
(or (null? x)
(and (pair? x)
(if (null? (cdr x))
(identifier/#f? (car x))
(and (id? (car x))
(id/#f-list? id? (cdr x)))))))
(and (list? x)
(= (length x) 6)
(identifier/#f? (car x))
(identifier/#f? (cadr x))
(identifier/#f? (caddr x))
(id/#f-list? identifier? (list-ref x 3))
(id/#f-list? identifier/#f? (list-ref x 4))
(or (eq? #t (list-ref x 5)) (identifier/#f? (list-ref x 5)))))
(define (build-name id . parts)
(datum->syntax-object
id
(string->symbol
(apply string-append
(map (lambda (p)
(if (syntax? p)
(symbol->string (syntax-e p))
p))
parts)))
id))
(define (bad why kw where)
(raise-syntax-error
#f
(format "~a ~a specification~a"
why
(syntax-e kw)
where)
stx
kw))
(define (check-exprs n ps)
(let loop ([nps (cdr ps)][n n])
(unless (zero? n)
(unless (and (pair? nps)
(not (keyword? (syntax-e (car nps)))))
(raise-syntax-error
#f
(format "expected ~a expression~a after keyword~a"
n
(if (= n 1) "" "s")
(if (pair? nps)
", found a keyword"
""))
stx
(car ps)))
(loop (cdr nps) (sub1 n)))))
;; Parse one field with a sequence of keyword-based specs:
(define (parse-field f)
(syntax-case f ()
[id
(identifier? #'id)
(make-field #'id #f #f #f)]
[(id p ...)
(identifier? #'id)
(let loop ([ps (syntax->list #'(p ...))]
[def-val #f]
[auto? #f]
[immutable? #f])
(cond
[(null? ps) (make-field #'id def-val auto? immutable?)]
[(eq? #:immutable (syntax-e (car ps)))
(when immutable?
(bad "redundant" (car ps) " for field"))
(loop (cdr ps) def-val auto? #t)]
[(eq? #:default (syntax-e (car ps)))
(check-exprs 1 ps)
(when def-val
(bad "multiple" (car ps) " for field"))
(loop (cddr ps) (cadr ps) auto? immutable?)]
[(eq? #:auto (syntax-e (car ps)))
(when auto?
(bad "redundant" (car ps) " for field"))
(loop (cdr ps) def-val #t immutable?)]
[else
(raise-syntax-error
#f
(if (keyword? (syntax-e (car ps)))
"unrecognized field-specification keyword"
"expected a field-spefication keyword")
stx
(car ps))]))]
[_else
(raise-syntax-error
#f
"expected a field identifier or a parenthesized identifier and field-specification sequence"
stx
f)]))
(define (lookup config s)
(cdr (assq s config)))
(define (extend-config config s val)
(cond
[(null? config) (error 'struct "internal error: can't find config element: ~s" s)]
[(eq? (caar config) s) (cons (cons s val) (cdr config))]
[else (cons (car config) (extend-config (cdr config) s val))]))
;; Parse sequence of keyword-based struct specs
(define (parse-props p super-id)
(let loop ([p p]
[config '((#:super . #f)
(#:inspector . #f)
(#:auto-value . #f)
(#:props . ())
(#:immutable . #f)
(#:guard . #f)
(#:omit-define-values . #f)
(#:omit-define-syntaxes . #f))])
(cond
[(null? p) config]
[(eq? #:super (syntax-e (car p)))
(check-exprs 1 p)
(when (lookup config '#:super)
(bad "multiple" (car p) ""))
(when super-id
(raise-syntax-error
#f
(string-append
"#:super specification disallowed because a struct supertype id"
" was supplied with the struct type id")
stx
(car p)))
(loop (cddr p)
(extend-config config '#:super (cadr p)))]
[(memq (syntax-e (car p))
'(#:inspector #:guard #:auto-value))
(let ([key (syntax-e (car p))])
(check-exprs 1 p)
(when (lookup config key)
(bad "multiple" (car p) ""))
(loop (cddr p)
(extend-config config key (cadr p))))]
[(eq? #:property (syntax-e (car p)))
(check-exprs 2 p)
(loop (cdddr p)
(extend-config config
'#:props
(cons (cons (cadr p) (caddr p))
(lookup config '#:props))))]
[(memq (syntax-e (car p))
'(#:immutable #:omit-define-values #:omit-define-syntaxes))
(let ([key (syntax-e (car p))])
(when (lookup config key)
(bad "redundant" (car p) ""))
(loop (cdr p)
(extend-config config key #t)))]
[else
(raise-syntax-error
#f
(if (keyword? (syntax-e (car p)))
"unrecognized struct-specification keyword"
"expected a struct-spefication keyword")
stx
(car p))])))
(syntax-case stx ()
[(fm id (field ...) prop ...)
(let-values ([(id super-id)
(if (identifier? #'id)
(values #'id #f)
(syntax-case #'id ()
[(id super-id)
(and (identifier? #'id)
(identifier? #'super-id))
(values #'id #'super-id)]
[else
(raise-syntax-error
#f
(string-append
"expected an identifier for the struct type name, or a parenthesized sequence"
" with an identifier followed by the struct supertype identifier")
stx)]))])
(let ([super-info
(and super-id
(let ([v (syntax-local-value super-id (lambda () #f))])
(if (struct-declaration-info? v)
v
(raise-syntax-error
#f
(format "parent struct type not defined~a"
(if v
(format " (~a does not name struct type information)"
(syntax-e super-id))
""))
stx
super-id))))])
(when (and super-info
(not (car super-info)))
(raise-syntax-error
#f
"no structure type descriptor available for supertype"
stx
super-id))
(let* ([field-stxes (syntax->list #'(field ...))]
[fields (map parse-field field-stxes)]
[dup (check-duplicate-identifier (map field-id fields))])
(when dup
(raise-syntax-error
#f
"duplicate field identifier"
stx
dup))
(let ([auto-count
(let loop ([fields fields] [field-stxes field-stxes] [auto? #f])
(cond
[(null? fields) 0]
[(field-auto? (car fields))
(+ 1 (loop (cdr fields) (cdr field-stxes) #t))]
[auto?
(raise-syntax-error
#f
"non-auto field after an auto field disallowed"
stx
(car field-stxes))]
[else
(loop (cdr fields) (cdr field-stxes) #f)]))])
(let-values ([(inspector super-expr props auto-val guard immutable?
omit-define-values? omit-define-syntaxes?)
(let ([config (parse-props (syntax->list #'(prop ...)) super-id)])
(values (lookup config '#:inspector)
(lookup config '#:super)
(lookup config '#:props)
(lookup config '#:auto-value)
(lookup config '#:guard)
(lookup config '#:immutable)
(lookup config '#:omit-define-values)
(lookup config '#:omit-define-syntaxes)))])
(when immutable?
(for-each (lambda (f f-stx)
(when (field-immutable? f)
(raise-syntax-error
#f
"redundant #:immutable specification in field"
stx
f-stx)))
fields field-stxes))
(let ([struct: (build-name id "struct:" id)]
[make- (build-name id "make-" id)]
[? (build-name id id "?")]
[sels (map (lambda (f)
(build-name (field-id f)
id "-" (field-id f)))
fields)]
[sets (if immutable?
null
(let loop ([fields fields])
(cond
[(null? fields) null]
[(field-immutable? (car fields))
(loop (cdr fields))]
[else
(cons (build-name (field-id (car fields))
"set-"
id
"-"
(field-id (car fields))
"!")
(loop (cdr fields)))])))]
[super-struct: (if super-info
(or (car super-info)
(raise-syntax-error
#f
"no structure type descriptor available for supertype"
stx
super-id))
(and super-expr
#`(check-struct-type 'fm #,super-expr)))])
(let ([run-time-defns
(lambda ()
(quasisyntax/loc stx
(define-values (#,struct: #,make- #,? #,@sels #,@sets)
(let-values ([(struct: make- ? -ref -set!)
(syntax-parameterize ([struct-field-index
(lambda (stx)
(syntax-case stx #,(map field-id fields)
#,@(let loop ([fields fields][pos 0])
(cond
[(null? fields) null]
[else (cons #`[(_ #,(field-id (car fields))) #'#,pos]
(loop (cdr fields) (add1 pos)))]))
[(_ name) (raise-syntax-error #f "no such field" stx #'name)]))])
(make-struct-type '#,id
#,super-struct:
#,(- (length fields) auto-count)
#,auto-count
#,auto-val
#,(if (null? props)
#'null
#`(list #,@(map (lambda (p)
#`(cons #,(car p) #,(cdr p)))
props)))
#,(if inspector
#`(check-inspector 'fm #,inspector)
#`(current-inspector))
#f
'#,(let loop ([i 0]
[fields fields])
(cond
[(null? fields) null]
[(or immutable? (field-immutable? (car fields)))
(cons i (loop (add1 i) (cdr fields)))]
[else (loop (add1 i) (cdr fields))]))
#,guard))])
(values struct: make- ?
#,@(let loop ([i 0][fields fields])
(if (null? fields)
null
(cons #`(make-struct-field-accessor -ref #,i '#,(field-id (car fields)))
(loop (add1 i) (cdr fields)))))
#,@(if immutable?
null
(let loop ([i 0][fields fields])
(if (null? fields)
null
(if (field-immutable? (car fields))
(loop (add1 i) (cdr fields))
(cons #`(make-struct-field-mutator -set! #,i '#,(field-id (car fields)))
(loop (add1 i) (cdr fields))))))))))))]
[compile-time-defns
(lambda ()
(let ([protect (lambda (sel)
(if (syntax-e sel)
#`(c (quote-syntax #,sel))
sel))])
(quasisyntax/loc stx
(define-syntaxes (#,id)
(let ([c (syntax-local-certifier)])
(list-immutable
(c (quote-syntax #,struct:))
(c (quote-syntax #,make-))
(c (quote-syntax #,?))
(list-immutable
#,@(map protect sels)
#,@(if super-info
(map protect (list-ref super-info 3))
(if super-expr
'(#f)
null)))
(list-immutable
#,@(let loop ([fields fields][sets sets])
(cond
[(null? fields) null]
[(or immutable? (field-immutable? (car fields)))
(cons #f (loop (cdr fields) sets))]
[else
(cons (protect (car sets))
(loop (cdr fields) (cdr sets)))]))
#,@(if super-info
(map protect (list-ref super-info 4))
(if super-expr
'(#f)
null)))
#,(if super-id
(protect super-id)
(if super-expr
#f
#t))))))))])
(cond
[(and (not omit-define-values?) (not omit-define-syntaxes?))
#`(begin #,(run-time-defns) #,(compile-time-defns))]
[omit-define-syntaxes?
(run-time-defns)]
[omit-define-values?
(compile-time-defns)]
[else #'(begin)]))))))))])))

View File

@ -1,7 +1,3 @@
(0 () 0 () () (c! require c! (c! lib c! "slideshow.ss" c! "slideshow")))
(0 () 0 () () (void))
(0 () 0 () () (c! require-for-syntax c! mzscheme))
(0 () 0 () () (void))
(0 () 0 () () 5)
(0 () 0 () () 5)
(0 () 0 () () "art gallery")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 B

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 B

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 837 B

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 B

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 236 B

View File

@ -0,0 +1,18 @@
(module mred-doc mzscheme
(define mr-eval? (getenv "MREVAL"))
(define-syntax bounce
(syntax-rules ()
[(_ id)
(begin
(provide id)
(define id (if mr-eval?
(dynamic-require '(lib "mred.ss" "mred") 'id)
#f)))]
[(_ id ...)
(begin (bounce id) ...)]))
(bounce frame% canvas%
bitmap% bitmap-dc%
color%))

View File

@ -7,6 +7,8 @@
(lib "file.ss")
(lib "runtime-path.ss")
(lib "serialize.ss")
"slideshow-doc.ss"
"mred-doc.ss"
(lib "exn.ss" "scribblings" "quick"))
(define-syntax define-mr
@ -17,8 +19,7 @@
(define-syntax mr
(syntax-rules ()
[(_ x (... ...))
(parameterize ([scribble-eval-handler mr-eval-handler]
[current-int-namespace mr-namespace])
(parameterize ([scribble-eval-handler mr-eval-handler])
(orig x (... ...)))])))]))
(define-mr mr-interaction interaction)
@ -46,7 +47,7 @@
(let ([eh (scribble-eval-handler)]
[log-file (open-output-file exprs-dat-file 'truncate/replace)])
(lambda (catching-exns? expr)
(write (serialize expr) log-file)
(write (serialize (syntax-object->datum expr)) log-file)
(newline log-file)
(flush-output log-file)
(let ([result
@ -76,7 +77,7 @@
(if (eof-object? v)
(error "expression not in log file")
(let ([v (deserialize v)])
(if (equal? v expr)
(if (equal? v (syntax-object->datum expr))
(let ([v (read log-file)])
(if (eof-object? v)
(error "expression result missing in log file")
@ -91,50 +92,22 @@
expr
v))))))))))
(define mr-namespace
(if mred?
((dynamic-require '(lib "mred.ss" "mred") 'make-namespace-with-mred))
(let ([ns (make-namespace)])
(namespace-attach-module (current-namespace)
'(lib "struct.ss" "scribble")
ns)
(namespace-attach-module (current-namespace)
'(lib "exn.ss" "scribblings" "quick")
ns)
ns)))
(define mr-namespace (current-namespace))
(define image-counter 0)
(define (ss:pict?)
(with-handlers ([exn:fail? (lambda (x) (lambda (x) #f))])
(eval 'pict? mr-namespace)))
(define (ss:pict-width)
(eval 'pict-width mr-namespace))
(define (ss:pict-height)
(eval 'pict-height mr-namespace))
(define (ss:make-pict-drawer)
(eval 'make-pict-drawer mr-namespace))
(define (ss:colorize)
(eval 'colorize mr-namespace))
(define (mred:canvas%)
(dynamic-require '(lib "mred.ss" "mred") 'canvas%))
(define (mred:bitmap%)
(dynamic-require '(lib "mred.ss" "mred") 'bitmap%))
(define (mred:bitmap-dc%)
(dynamic-require '(lib "mred.ss" "mred") 'bitmap-dc%))
(define (fixup-picts v)
(cond
[((ss:pict?) v)
[(pict? v)
(let ([fn (format "~a/img~a.png" img-dir image-counter)])
(set! image-counter (add1 image-counter))
(let* ([bm (make-object (mred:bitmap%)
(inexact->exact (ceiling ((ss:pict-width) v)))
(inexact->exact (ceiling ((ss:pict-height) v))))]
[dc (make-object (mred:bitmap-dc%) bm)])
(let* ([bm (make-object bitmap%
(inexact->exact (ceiling (pict-width v)))
(inexact->exact (ceiling (pict-height v))))]
[dc (make-object bitmap-dc% bm)])
(send dc set-smoothing 'aligned)
(send dc clear)
(((ss:make-pict-drawer) v) dc 0 0)
((make-pict-drawer (colorize v (make-object color% 0 0 #xAF))) dc 0 0)
(send bm save-file fn 'png)
(make-element #f (list (make-element (make-image-file fn) (list "[image]"))))))]
[(pair? v) (cons (fixup-picts (car v))

View File

@ -7,9 +7,16 @@
@require[(lib "manual.ss" "scribble")]
@require["mreval.ss"]
@require[(lib "urls.ss" "scribble")]
@require[(lib "class.ss")]
@require["slideshow-doc.ss"]
@require["slideshow-code-doc.ss"]
@require["mred-doc.ss"]
@require-for-syntax[mzscheme]
@mr-interaction-eval[(require (lib "slideshow.ss" "slideshow"))]
@mr-interaction-eval[(require-for-syntax mzscheme)]
@define[filled-flash (lambda args (apply (eval 'filled-flash) args))]
@define[random-gaussian (lambda args (apply (eval 'random-gaussian) args))]
@define-syntax[code (syntax-rules () [(_ v) (typeset-code (quote-syntax v))])]
@provide[filled-flash random-gaussian code]
@; ----------------------------------------------------------------------
@section{Why Pictures? Why DrScheme?}

View File

@ -0,0 +1,18 @@
(module slideshow-code-doc mzscheme
(require (only "slideshow-doc.ss"))
(define mr-eval? (getenv "MREVAL"))
(define-syntax bounce
(syntax-rules ()
[(_ id)
(begin
(provide id)
(define id (if mr-eval?
(dynamic-require '(lib "code.ss" "slideshow") 'id)
#f)))]
[(_ id ...)
(begin (bounce id) ...)]))
(bounce typeset-code))

View File

@ -0,0 +1,30 @@
(module slideshow-doc mzscheme
(define mr-eval? (getenv "MREVAL"))
(when mr-eval?
(parameterize ([current-command-line-arguments #()])
(dynamic-require '(lib "slideshow.ss" "slideshow") #f)))
(define-syntax bounce
(syntax-rules ()
[(_ id)
(begin
(provide id)
(define id (if mr-eval?
(dynamic-require '(lib "slideshow.ss" "slideshow") 'id)
#f)))]
[(_ id ...)
(begin (bounce id) ...)]))
(bounce circle
rectangle
hc-append
filled-rectangle
vc-append
colorize
scale
bitmap
make-pict-drawer
pict? pict-width pict-height))

View File

@ -1,7 +1,6 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@interaction-eval[(require (lib "for.ss"))]
@require[(lib "for.ss")]
@title[#:tag "mz:for"]{Iterations and Comprehensions: @scheme[for], @scheme[for/list], ...}

View File

@ -497,11 +497,13 @@ forms. As a result, future references of the @tech{variable} always
access the same @tech{location}.
@;------------------------------------------------------------------------
@section{Modules and Module-Level Variables}
@section[#:tag "mz:module-eval-model"]{Modules and Module-Level Variables}
Most definitions in PLT Scheme are in modules. In terms of evaluation,
a module is essentially a prefix on a defined name, so that different
modules can define the name.
modules can define the name. That is, a @deftech{module-level
variable} is like a @tech{top-level variable} from the perspective of
evaluation.
One difference between a module an a top-level definition is that a
module can be declared without instantiating its module-level
@ -621,7 +623,7 @@ is created) as all other threads.
@;------------------------------------------------------------------------
@section{Parameters}
A @deftech{parameter} is essentially a derived concept in Scheme; they
@deftech{Parameters} are essentially a derived concept in Scheme; they
are defined in terms of continuation marks and thread cells. However,
parameters are also built in, in the sense that some primitive
procedures consult parameter values. For example, the default output

View File

@ -5,8 +5,6 @@
(lib "decode.ss" "scribble")
(lib "kw.ss"))
(interaction-eval (require (lib "new-lambda.ss" "scribblings")))
(provide (all-from (lib "manual.ss" "scribble"))
(all-from (lib "eval.ss" "scribble")))

View File

@ -19,8 +19,8 @@
Scheme's reader is a recursive-descent parser that can be configured
through a @seclink["mz:readtables"]{readtable} and various other
@seclink["parameters"]{parameters}. This section describes the reader's
parsing when using the default readtable.
@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
@ -28,7 +28,7 @@ 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 @seclink["stxobj"]{syntax object} that includes
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
@ -164,7 +164,7 @@ 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] parameter is set to @scheme[#f],
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},
@ -202,7 +202,7 @@ which specifies its parsing as an exact or inexact number; see
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] parameter is set to @scheme[#f], then
@scheme[read-decimal-as-inexact] @tech{parameter} is set to @scheme[#f], then
all numbers without an exactness specifier are instead parsed as
exact.
@ -344,10 +344,10 @@ being parsed, then the @exnraise[exn:fail:read].
"(1 . 2 . 3)"
]
If the @scheme[read-square-bracket-as-paren] parameter is set to
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] parameter is set to @scheme[#f],
@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}.
@ -701,7 +701,7 @@ 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] parameter; the result is used as a
@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]
@ -718,7 +718,7 @@ 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] parameter is set to @scheme[#f],
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].

View File

@ -1,10 +1,9 @@
(module reader-example mzscheme
(module reader-example (lib "new-lambda.ss" "scribblings")
(require (lib "struct.ss" "scribble")
(lib "decode.ss" "scribble")
(lib "manual.ss" "scribble")
(lib "scheme.ss" "scribble")
(lib "kw.ss")
(lib "class.ss"))
(provide reader-examples
@ -22,10 +21,9 @@
(define spacer (hspace 1))
(define/kw (reader-examples #:key
[symbols? #t]
[example-note ""]
#:body strs)
(define (reader-examples #:symbols? [symbols? #t]
#:example-note [example-note ""]
. strs)
(make-table
#f
(list
@ -125,7 +123,7 @@
(define (dispatch a . b)
(list a (make-element #f (decode-content b))))
(define/kw (metavar #:body s)
(define (metavar . s)
(make-element 'italic (decode-content s)))
(define (cilitchar s)

View File

@ -308,9 +308,9 @@ things:
identifier (third case in the previous enumeration), and
parsing continues.}
@item{A core syntactic form, which is parsed as described for each
form in @secref["mz:syntax"]. Parsing a core syntactic form
typically involves recursive parsing of sub-forms, and may
@item{A core @deftech{syntactic form}, which is parsed as described
for each form in @secref["mz:syntax"]. Parsing a core syntactic
form typically involves recursive parsing of sub-forms, and may
introduce @tech{bindings} that determine the parsing of
sub-forms.}
@ -340,7 +340,7 @@ contexts. The possible @tech{contexts} are as follows:
@item{@deftech{internal-definition context} : in a nested context that allows
both definitions and expressions.}
@item{@deftech{expression content} : in a context where only
@item{@deftech{expression context} : in a context where only
expressions are allowed.}
}
@ -440,10 +440,10 @@ be @tech{expand}ed (i.e. parsed) before it can be evaluated, and it is
expanded at @tech{phase level} 1 instead of @tech{phase level} 0.
The if resulting @scheme[value] is a procedure of one argument, then
is it used as a @deftech{transformer procedure}. The procedure is
is it used as a @deftech{syntax transformer}. The procedure is
expected to accept a syntax object and return a syntax object. A use
of the binding (at @tech{phase level} 0) triggers a call of the
@tech{transformer procedure} by the expander; see
@tech{syntax transformer} by the expander; see
@secref["mz:expand-steps"].
Before the expander passes a @tech{syntax object} to a transformer,
@ -547,7 +547,7 @@ If the last expression form turns out to be a @scheme[define-values]
or @scheme[define-syntaxes] form, expansion fails with a syntax error.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection{Module Phases}
@subsection[#:tag "mz:mod-parse"]{Module Phases}
A @scheme[require] form not only introduces @tech{bindings} at
expansion time, but also @deftech{visits} the referenced module when

View File

@ -50,6 +50,48 @@ Within such specifications,
}} }
@;------------------------------------------------------------------------
@section{Literals: @scheme[quote] and @scheme[#%datum]}
@defform[(quote datum)]{
Produces a constant value corresponding to @scheme[datum] (i.e., the
actual representation of the program fragment) without its
@tech{lexical information} or source location.
@examples[
(eval:alts (#,(schemekeywordfont "quote") x) 'x)
(eval:alts (#,(schemekeywordfont "quote") (+ 1 2)) '(+ 1 2))
]
}
@defform[(#%datum . datum)]{
Expands to @scheme[(#,(schemekeywordfont "quote") datum)]. See also @secref["mz:expand-steps"]
for information on how the expander introduces @schemeidfont{#%datum}
identifiers.
@examples[
(#%datum . 10)
(#%datum . x)
]
}
@;------------------------------------------------------------------------
@section{Expression Wrapper: @scheme[#%expression]}
@defform[(#%expression expr)]{
Produces the same result as @scheme[expr]. The only use of
@scheme[#%expression] is to force the parsing of a form as an
expression.
@examples[
(#%expression (+ 1 2))
(#%expression (define x 10))
]}
@;------------------------------------------------------------------------
@section{Variable References and @scheme[#%top]}
@ -64,7 +106,7 @@ When the expander encounters an @scheme[id] that is not bound by a
module-level or local binding, it converts the expression to @scheme[(#,
@schemeidfont{#%top} . id)] giving @schemeidfont{#%top} the lexical
context of the @scheme[id]; typically, that context refers to
@scheme[#%top].
@scheme[#%top]. See also @secref["mz:expand-steps"].
@examples[
(define x 10)
@ -75,15 +117,31 @@ x
@defform[(#%top . id)]{
Refers to a top-level definition that could bind @scheme[id],
even if @scheme[id] has a local binding in its context. Such
references are disallowed anywhere within a @scheme[module] form.
Refers to a top-level definition that could bind @scheme[id], even if
@scheme[id] has a local binding in its context. Such references are
disallowed anywhere within a @scheme[module] form. See also
@secref["mz:expand-steps"] for information on how the expander
introduces @schemeidfont{#%top} identifiers.
@examples[
(define x 12)
(let ([x 5]) (#%top . x))
]}
@;------------------------------------------------------------------------
@section{Locations: @scheme[#%variable-reference]}
@defform*[#:literals (#%top)
[(#%variable-reference id)
(#%variable-reference (#%top . id))]]{
Produces an opaque value representing the location of @scheme[id],
which must be bound as a @tech{top-level variable} or
@tech{module-level variable}.
The result is useful only to low-level extensions; see
@secref["inside-mzscheme"].}
@;------------------------------------------------------------------------
@section[#:tag "mz:application"]{Procedure Applications and @scheme[#%app]}
@ -100,7 +158,8 @@ More precisely, the expander converts this form to @scheme[(#,
the lexical context that is associated with the original form (i.e.,
the pair that combines @scheme[proc-expr] and its
arguments). Typically, the lexical context of the pair indicates the
procedure-application @scheme[#%app] that is described next.
procedure-application @scheme[#%app] that is described next. See also
@secref["mz:expand-steps"].
@examples[
(+ 1 2)
@ -138,6 +197,9 @@ the @scheme[_keyword]s, and not their positions. The other
@scheme[_arg-expr] values, in contrast, are associated with variables
according to their order in the application form.
See also @secref["mz:expand-steps"] for information on how the
expander introduces @schemeidfont{#%app} identifiers.
@examples[
(#%app + 1 2)
(#%app (lambda (x #:arg y) (list y x)) #:arg 2 1)
@ -442,8 +504,8 @@ using the @|cvt| meta-function defined as follows:
At the top level, the top-level binding @scheme[id] is created after
evaluating @scheme[expr], if it does not exist already, and the
top-level mapping of @scheme[id] (see @secref["mz:namespace"]) is set
to the binding at the same time.
top-level mapping of @scheme[id] (in the @techlink{namespace} linked
with the compiled definition) is set to the binding at the same time.
@defexamples[
(define x 10)
@ -472,8 +534,9 @@ the @exnraise[exn:fail:contract].
At the top level, the top-level binding for each @scheme[id] is
created after evaluating @scheme[expr], if it does not exist already,
and the top-level mapping of each @scheme[id] (see
@secref["mz:namespace"]) is set to the binding at the same time.
and the top-level mapping of each @scheme[id] (in the
@techlink{namespace} linked with the compiled definition) is set to
the binding at the same time.
@defexamples[
(define-values () (values))
@ -526,6 +589,42 @@ in tail position only if no @scheme[body]s are present.
(printf "hi\n"))
]}
@;------------------------------------------------------------------------
@section{Assignment: @scheme[set!] and @scheme[set!-values]}
@defform[(set! id expr)]{
Evaluates @scheme[expr] and installs the result into the location for
@scheme[id], which must be bound as a local variable or defined as a
@tech{top-level variable} or @tech{module-level variable}. If
@scheme[id] refers to a @tech{top-level variable} that has not been
defined, the @exnraise[exn:fail:contract].
@defexamples[
(define x 12)
(set! x (add1 x))
x
(let ([x 5])
(set! x (add1 x))
x)
(set! i-am-not-defined 10)
]}
@defform[(set!-values (id ...) expr)]{
Evaluates @scheme[expr], which must produce as many values as supplied
@scheme[id]s. The location of each @scheme[id] is filled wih to the
corresponding value from @scheme[expr] in the same way as for
@scheme[set!].
@examples[
(let ([a 1]
[b 2])
(set!-values (a b) (values b a))
(list a b))
]}
@;------------------------------------------------------------------------
@section{Continuation Marks: @scheme[with-continuation-mark]}
@ -540,11 +639,196 @@ current continuation frame (see @secref["mz:contmarks"]), and then
@section{Syntax Quoting: @scheme[quote-syntax]}
@defform[(quote-syntax datum)]{
Produces a syntax object that preserves
lexical and source-location information attached to @scheme[datum]
at expansion time.
Produces a @tech{syntax object} that preserves the @tech{lexical
information} and source-location information attached to
@scheme[datum] at expansion time.
@examples[
(syntax? (quote-syntax x))
]
}
}
@;------------------------------------------------------------------------
@section[#:tag "mz:require"]{Importing: @scheme[require], @scheme[require-for-syntax], @scheme[require-for-template]}
@defform/subs[#:literals (only prefix all-except prefix-all-except rename lib file planet)
(require require-spec ...)
([require-spec module-path
(only require-spec id-maybe-renamed ...)
(except require-spec id ...)
(prefix require-spec prefix-id)
(rename require-spec [orig-id bind-id] ...)]
[module-path id
rel-string
(lib rel-string)
(file string)
(planet rel-string (user-string pkg-string vers ...))]
[id-maybe-renamed id
[orig-id bind-id]]
[vers nat
(nat nat)
(= nat)
(+ nat)
(- nat)])]{
In a @tech{top-level context}, @scheme[require] instantiates modules
(see @secref["mz:module-eval-model"]). In a @tech{module context},
@scheme[require] visits modules (see @secref["mz:mod-parse"]). In both
contexts, @scheme[require] introduces bindings into a @tech{namespace}
or a module (see @secref["mz:intro-binding"]). A @scheme[require] form
in a @tech{expression context} or @tech{internal-definition context}
is a syntax error.
A @scheme[require-spec] designates a particular set of identifiers to
be bound in the importing context. Each identifier is mapped to a
particular export of a particular module; the identifier to bind may
be different from the symbolic name of the originally exported
identifier.
@specsubform[module-path]{ Imports all exported bindings from the
named module, using the export identifier as the local identifiers.}
@specsubform[#:literals (only) (only require-spec id-maybe-renamed ...)]{
Like @scheme[require-spec], but constrained to those exports for
which the identifiers to bind match @scheme[id-maybe-renamed]: as
@scheme[id] or as @scheme[orig-id] in @scheme[[orig-id bind-id]]. If
the @scheme[id] of @scheme[orig-id] of any @scheme[id-maybe-renamed]
is not in the set that @scheme[require-spec] describes, a syntax
error is reported.}
@specsubform[#:literals (except) (except require-spec id ...)]{ Like
@scheme[require-spec], but omitting those exports for which
@scheme[id]s are the identifiers to bind; if any @scheme[id] is not
in the set that @scheme[require-spec] describes, a syntax error is
reported.}
@specsubform[#:literals (prefix) (prefix require-spec prefix-id)]{
Like @scheme[require-spec], but adjusting each identifier to be bound
by prefixing it with @scheme[prefix-id].}
@specsubform[#:literals (rename)
(rename require-spec [orig-id bind-id] ...)]{
Like @scheme[require-spec], but replacing the identifier to
bind @scheme[orig-id] with @scheme[bind-id]; if any
@scheme[orig-id] is not in the set that @scheme[require-spec]
describes, a syntax error is reported.}
A @scheme[module-path] identifies a module, either through a concrete
name in the form of an identifier, or through an indirect name that
can trigger automatic loading of the module declaration:
@specsubform[id]{ Refers to a module previously declared with the name
@scheme[id].}
@specsubform[rel-string]{A path relative to the containing source (as
determined by @scheme[current-load-relative-directory] or
@scheme[current-directory]). Regardless of the current platform,
@scheme[rel-string] is always parsed as a Unix-format relative path:
@litchar{/} is the path delimiter (multiple adjacent @litchar{/}s are
treated as a single delimiter), @litchar{..} accesses the parent
directory, and @litchar{.} accesses the current directory. The path
cannot be empty or contain a leading or trailing slash.}
@specsubform[#:literals (lib) (lib rel-string)]{Like the plain
@scheme[rel-string] case, but @scheme[rel-string] must contain at
least two path elements. All path elements up to the last one form a
@tech{collection} path, which is used to locate the relevant
directory (not relative to the containing source), and the last path
element refers to a file.}
@specsubform[#:literals (file) (file string)]{Similar to the plain
@scheme[rel-string] case, but @scheme[string] is a path (possibly
absolute) using the current platform's path conventions.}
@specsubform[#:literals(planet)
(planet rel-string (user-string pkg-string vers ...))]{
Specifies a library available via the @PLaneT server.
}
No identifier can be bound multiple times by an import, unless all of
the bindings refer to the same original definition in the same module.
In a @tech{module context}, an identifier can be either imported or
defined for a given @tech{phase level}, but not both.}
@defform[(require-for-syntax require-spec ...)]{
Like @scheme[require], but @tech{instantiate}s a module at phase 1
(see @secref["mz:module-eval-model"]) in a @tech{top-level context} or
@tech{module context}, and introduces bindings at phase level 1 (see
@secref["mz:intro-binding"] and @secref["mz:mod-parse"]).
}
@defform[(require-for-template require-spec ...)]{ Like
@scheme[require], but without @tech{instantiation} (see
@secref["mz:module-eval-model"]) in a @tech{top-level context}, and
introduces bindings at phase level -1 (see @secref["mz:intro-binding"]
and @secref["mz:mod-parse"]).
}
@;------------------------------------------------------------------------
@section{Exporting: @scheme[provide] and @scheme[provide-for-syntax]}
@defform/subs[#:literals (protect all-defined all-from rename except prefix)
(provide protected-provide-spec ...)
([protected-provide-spec provide-spec
(protect provide-spec)]
[provide-spec id
(all-defined)
(all-from module-name)
(rename [orig-id export-id] ...)
(except provide-spec id ...)
(prefix provide-spec prefix-id)])]{
Declares exports from a module. A @scheme[provide] form must appear in
a @tech{module context} or a @tech{module-begin} context.
A @scheme[provide-spec] indicates one or more bindings to provide,
specifying for each an export symbol that can be different from
the symbolic form of the identifier bound within the module:
@specsubform[id]{ Exports @scheme[id], which must be @tech{bound}
within the module (i.e., either defined or imported), at @tech{phase
level} 0 using the symbolic form of @scheme[id] as the external
name.}
@specsubform[#:literals (all-defined) (all-defined)]{ Exports all
identifiers that are defined at @tech{phase level} 0 within the
exporting module. The external name for each identifier is the
symbolic form of the identifier; note that this can lead to an
illegal multiple export for a single symbolic name if different
defined identifiers use the same symbolic name.}
@specsubform[#:literals (all-from) (all-from module-name)]{ Exports
all identifiers that are imported into the exporting module at
@tech{phase level} 0 using a @scheme[require-spec] built on
@scheme[module-name] (see @secref["mz:require"]). The symbolic name
for export is derived from the name that is bound within the module,
as opposed to the symbolic name of the export from
@scheme[module-name].}
@specsubform[#:literals (rename) (rename [orig-id export-id] ...)]{
Exports each @scheme[orig-id], which must be @tech{bound} within the
module at @tech{phase level} 0. The symbolic name for each export is
@scheme[export-id] instead @scheme[orig-d].}
@specsubform[#:literals (except) (except provide-spec id ...)]{ Like
@scheme[provide-spec], but omitting an export for each binding
@scheme[id]. If @scheme[id] is not specified as an export by
@scheme[provide-spec], a syntax error is reported.}
@specsubform[#:literals (prefix) (prefix provide-spec prefix-id)]{
Like @scheme[provide-spec], but with each symbolic export name from
@scheme[provide-spec] prefixed with @scheme[prefix-id].}
If @scheme[provide] wraps a @scheme[provide-spec], then the exports of
the @scheme[provide-spec] are protected; see
@secref["mz:protected-exports"]. The @scheme[provide-spec] must
specify only bindings that are defined within the exporting module.
Each export specified within a module must have a distinct symbolic
export name, though the same binding can be specified with the
multiple symbolic names.}
@defform[(provide-for-syntax protected-provide-spec ...)]{Like
@scheme[provide], but exports at @tech{phase level} 1 bindings within
the module at @tech{phase level} 1.}

View File

@ -10,24 +10,24 @@ especially to show example uses of defined procedures and syntax.
@defform[(interaction datum ...)]{Like @scheme[schemeinput], except
that the result for each input @scheme[datum] is shown on the next
line. The result is determined by evaluating the quoted form of the
datum.
line. The result is determined by evaluating the syntax-quoted form of
the @scheme[datum].
Uses of @scheme[code:comment] and @schemeidfont{code:blank} are
stipped from each @scheme[datum] before evaluation.
If a datum has the form @scheme[(#,(scheme code:line) #,(svar datum)
(#,(scheme code:comment) ...))], then only the @svar[datum] is
evaluated.
If a @scheme[datum] has the form @scheme[(#,(scheme code:line)
_code-datum (#,(scheme code:comment) ...))], then only
@scheme[_code-datum] is evaluated.
If a datum has the form @scheme[(eval:alts #,(svar show-datum) #,(svar
eval-datum))], then @svar[show-datum] is typeset, while
@svar[eval-datum] is evaluated.}
@defform[(interaction-eval datum)]{Evaluates the quoted form of
@defform[(interaction-eval datum)]{Evaluates the syntax-quoted form of
each @scheme[datum] via @scheme[do-eval] and returns the empty string.}
@defform[(interaction-eval-show datum)]{Evaluates the quoted form of
@defform[(interaction-eval-show datum)]{Evaluates the syntax-quoted form of
@scheme[datum] and produces an element represeting the printed form of
the result.}

View File

@ -14,7 +14,7 @@ more...
@defform[(schemeblock datum ...)]{
Typesets the @scheme[datum] sequence as a table of Scheme code inset
by two spaces. The source locations of the @scheme[datum]s determines
by two spaces. The source locations of the @scheme[datum]s determine
the generated layout. For example,
@schemeblock[
@ -32,10 +32,13 @@ produces the output
with the @scheme[(loop (not x))] indented under @scheme[define],
because that's the way it is idented the use of @scheme[schemeblock].
Furthermore, @scheme[define] is typeset as a keyword (bold and black)
and as a hyperlink to @scheme[define]'s definition in the reference
manual, because this document was built using information about the
MzScheme manual. Similarly, @scheme[not] is a hyperlink to the its
reference manual, and because the lexical binding of @scheme[define]
(in the source) matches the lexical binding of the definition in the
reference manual. Similarly, @scheme[not] is a hyperlink to the its
definition in the reference manual.
Use @scheme[unsyntax] to escape back to an expression that produces an
@ -127,7 +130,7 @@ useful with @scheme[verbatim].}
@defproc[(schemefont [pre-content any/c] ...) element?]{Typesets the given
content as uncolored, unhyperlinked Scheme. This procedure is useful
for typesetting thngs like @scheme{#module}, which are not
for typesetting things like @scheme{#module}, which are not
@scheme[read]able by themselves.}
@defproc[(schemevalfont [pre-content any/c] ...) element?]{Like
@ -143,7 +146,7 @@ for typesetting thngs like @scheme{#module}, which are not
@scheme[schemefont], but colored as a syntactic form name.}
@defproc[(procedure [pre-content any/c] ...) element?]{Typesets the given
content as a procedure name in a REPL result (e.g., in typewrite font
content as a procedure name in a REPL result (e.g., in typewriter font
with a @schemefont{#<procedure:} prefix and @schemefont{>} suffix.).}
@defform[(var datum)]{Typesets @scheme[var] as an identifier that is
@ -164,9 +167,9 @@ in a form definition.}
pre-flow ...)]{
Produces a sequence of flow elements (encaptured in a @scheme[splice])
to document a procedure named @scheme[id]. The
@scheme[id] is registered so that @scheme[scheme]-typeset uses
of the identifier are hyperlinked to this documentation.
to document a procedure named @scheme[id]. The @scheme[id] is
registered so that @scheme[scheme]-typeset uses of the identifier
(with the same lexical binding) are hyperlinked to this documentation.
Each @scheme[arg-spec] must have one of the following forms:
@ -213,39 +216,54 @@ Like @scheme[defproc], but for multiple cases with the same
@scheme[id]. }
@defform[(defform (id . datum) pre-flow ...)]{Produces a
a sequence of flow elements (encaptured in a @scheme[splice]) to
document a syntatic form named by @scheme[id]. The
@scheme[id] is registered so that @scheme[scheme]-typeset uses
of the identifier are hyperlinked to this documentation.
@defform/subs[(defform maybe-literals (id . datum) pre-flow ...)
([maybe-literals code:blank
(code:line #:literals (literal-id ...))])]{
Produces a a sequence of flow elements (encaptured in a
@scheme[splice]) to document a syntatic form named by @scheme[id]. The
@scheme[id] is registered so that @scheme[scheme]-typeset uses of the
identifier (with the same lexical binding) are hyperlinked to this
documentation.
The @scheme[pre-flow]s list is parsed as a flow that documents the
procedure. In this description, a reference to any identifier in
@scheme[datum] is typeset as a sub-form non-terminal.
@scheme[datum] is typeset as a sub-form non-terminal. If
@scheme[#:literals] clause is provided, however, instances of the
@scheme[literal-id]s are typeset normally.
The typesetting of @scheme[(id . datum)] preserves the source
layout, like @scheme[schemeblock], and unlike @scheme[defproc].}
@defform[(defform* [(id . datum) ..+] pre-flow ...)]{Like @scheme[defform],
but for multiple forms using the same @scheme[id].}
@defform[(defform* maybe-literals [(id . datum) ..+] pre-flow ...)]{
@defform[(defform/subs (id . datum)
([nonterm-id clause-datum ...+] ...)
pre-flow ...)]{
Like @scheme[defform], but for multiple forms using the same
@scheme[id].}
@defform/subs[(defform/subs maybe-literals (id . datum)
([nonterm-id clause-datum ...+] ...)
pre-flow ...)
([maybe-literals code:blank
(code:line #:literals (literal-id ...))])]{
Like @scheme[defform], but including an auxiliary grammar of
non-terminals shown with the @scheme[id] form. Each
@scheme[nonterm-id] is specified as being any of the corresponding
@scheme[clause-datum]s, where the formatting of each
@scheme[clause-datum] is preserved.}
@defform[(specform (id . datum) pre-flow ...)]{Like @scheme[defform],
with without registering a definition, and with indenting on the left
for both the specification and the @scheme[pre-flow]s.}
@defform/subs[(specform maybe-literals (id . datum) pre-flow ...)
([maybe-literals code:blank
(code:line #:literals (literal-id ...))])]{
@defform[(specsubform datum pre-flow ...)]{Similar to
@scheme[defform], but without any specific identifier being defined,
and the table and flow are typeset indented. This form is intended for
use when refining the syntax of a non-terminal used in a
Like @scheme[defform], with without registering a definition, and with
indenting on the left for both the specification and the
@scheme[pre-flow]s.}
@defform[(specsubform maybe-literals datum pre-flow ...)]{
Similar to @scheme[defform], but without any specific identifier being
defined, and the table and flow are typeset indented. This form is
intended for use when refining the syntax of a non-terminal used in a
@scheme[defform] or other @scheme[specsubform]. For example, it is
used in the documentation for @scheme[defproc] in the itemization of
possible shapes for @svar[arg-spec].
@ -254,8 +272,9 @@ The @scheme[pre-flow]s list is parsed as a flow that documents the
procedure. In this description, a reference to any identifier in
@scheme[datum] is typeset as a sub-form non-terminal.}
@defform[(defthing id contract-expr-datum pre-flow ...)]{Like
@scheme[defproc], but for a non-procedure binding.}
@defform[(defthing id contract-expr-datum pre-flow ...)]{
Like @scheme[defproc], but for a non-procedure binding.}
@defform/subs[(defstruct struct-name ([field-name contract-expr-datum] ...)
pre-flow ...)
@ -265,13 +284,19 @@ procedure. In this description, a reference to any identifier in
Similar to @scheme[defform] or @scheme[defproc], but for a structure
definition.}
@defform/subs[(schemegrammar literals ? id clause-datum ...+)
([literals (code:line #:literals (literal-id ...))])]{
Creates a table to define the grammar of @scheme[id]. Each identifier mentioned
in a @scheme[clause-datum] is typeset as a non-terminal, except for the
identifiers listed as @scheme[literal-id]s, which are typeset as with
@scheme[scheme].
}
@defform/subs[(schemegrammar maybe-literals id clause-datum ...+)
([maybe-literals code:blank
(code:line #:literals (literal-id ...))])]{
Creates a table to define the grammar of @scheme[id]. Each identifier
mentioned in a @scheme[clause-datum] is typeset as a non-terminal,
except for the identifiers listed as @scheme[literal-id]s, which are
typeset as with @scheme[scheme].}
@defform[(schemegrammar* maybe-literals [id clause-datum ...+] ...)]{
Like @scheme[schemegrammar], but for typesetting multiple productions
at once, aligned around the @litchar{=} and @litchar{|}.}
@; ------------------------------------------------------------------------
@section{Various String Forms}