sync to trunk

svn: r17249
This commit is contained in:
Sam Tobin-Hochstadt 2009-12-09 19:44:12 +00:00
commit cd0a94d465
185 changed files with 7606 additions and 3153 deletions

View File

@ -52,6 +52,9 @@ and they all have good sample contracts. (It is amazing what we can do with kids
(provide overlay
overlay/align
overlay/xy
underlay
underlay/align
underlay/xy
beside
beside/align

View File

@ -307,10 +307,14 @@
;; overlay : image image image ... -> image
;; places images on top of each other with their upper left corners aligned. last one goes on the bottom
(define/chk (overlay image image2 . image3)
(overlay/internal 'left 'top image (cons image2 image3)))
;; underlay : image image image ... -> image
(define (underlay image image2 . image3)
(let ([imgs (reverse (list* image image2 image3))])
(overlay/internal 'left 'top (car imgs) (cdr imgs))))
;; overlay/align : string string image image image ... -> image
;; the first string has to be one of "center" "middle" "left" or "right" (or symbols)
;; the second string has to be one of "center" "middle" "top" "bottom" or "baseline" (or symbols)
@ -322,6 +326,10 @@
(define/chk (overlay/align x-place y-place image image2 . image3)
(overlay/internal x-place y-place image (cons image2 image3)))
(define/chk (underlay/align x-place y-place image image2 . image3)
(let ([imgs (reverse (list* image image2 image3))])
(overlay/internal x-place y-place (car imgs) (cdr imgs))))
(define (overlay/internal x-place y-place fst rst)
(let loop ([fst fst]
[rst rst])
@ -346,14 +354,16 @@
(case x-place
[(left) 0]
[(middle) (/ (image-right image) 2)]
[(right) (image-right image)]))
[(right) (image-right image)]
[else (error 'find-x-spot "~s" x-place)]))
(define (find-y-spot y-place image)
(case y-place
[(top) 0]
[(middle) (/ (image-bottom image) 2)]
[(bottom) (image-bottom image)]
[(baseline) (image-baseline image)]))
[(baseline) (image-baseline image)]
[else (error 'find-y-spot "~s" y-place)]))
;; overlay/xy : image number number image -> image
;; places images on top of each other with their upper-left corners offset by the two numbers
@ -366,6 +376,14 @@
(if (< dx 0) 0 dx)
(if (< dy 0) 0 dy)))
(define/chk (underlay/xy image dx dy image2)
(overlay/δ image2
(if (< dx 0) 0 dx)
(if (< dy 0) 0 dy)
image
(if (< dx 0) (- dx) 0)
(if (< dy 0) (- dy) 0)))
(define (overlay/δ image1 dx1 dy1 image2 dx2 dy2)
(make-image (make-overlay (make-translate dx1 dy1 (image-shape image1))
(make-translate dx2 dy2 (image-shape image2)))
@ -943,6 +961,10 @@
(provide overlay
overlay/align
overlay/xy
underlay
underlay/align
underlay/xy
beside
beside/align
above

View File

@ -0,0 +1,5 @@
#lang scheme
(provide (struct-out stop-the-world))
(define-struct stop-the-world (world) #:transparent)

View File

@ -4,6 +4,7 @@
"timer.ss"
"last.ss"
"checked-cell.ss"
"stop.ss"
htdp/image
htdp/error
mzlib/runtime-path
@ -219,16 +220,26 @@
(when (package? nw)
(broadcast (package-message nw))
(set! nw (package-world nw)))
(let ([changed-world? (send world set tag nw)])
(unless changed-world?
(when draw (pdraw))
(when (pstop)
(when last-picture
(set! draw last-picture)
(pdraw))
(callback-stop! 'name)
(enable-images-button)))
changed-world?))))))
(if (stop-the-world? nw)
(begin
(set! nw (stop-the-world-world nw))
(send world set tag nw)
(when last-picture
(set! draw last-picture))
(when draw (pdraw))
(callback-stop! 'name)
(enable-images-button))
(let ([changed-world? (send world set tag nw)])
(unless changed-world?
(when draw (pdraw))
(when (pstop)
(printf "!stop!\n")
(when last-picture
(set! draw last-picture)
(pdraw))
(callback-stop! 'name)
(enable-images-button)))
changed-world?)))))))
;; tick, tock : deal with a tick event for this world
(def/pub-cback (ptock) tick)
@ -284,7 +295,11 @@
;; initialize the world and run
(super-new)
(start!)
(when (stop (send world get)) (stop! (send world get)))))))
(let ([w (send world get)])
(cond
[(stop w) (stop! (send world get))]
[(stop-the-world? w)
(stop! (stop-the-world-world (send world get)))]))))))
;; -----------------------------------------------------------------------------
(define-runtime-path break-btn:path '(lib "icons/break.png"))

View File

@ -0,0 +1,22 @@
;; The first three lines of this file were inserted by DrScheme. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname test-stop) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
(require 2htdp/universe)
;; on RETURN stop
(define (main debug?)
(big-bang ""
(on-key (lambda (w ke)
(cond
[(key=? ke "\r") (stop-with w)]
[(= (string-length ke) 1)
(string-append w ke)]
[else w])))
(state debug?)
(on-draw (lambda (w)
(place-image
(text w 22 'black)
3 3
(empty-scene 100 100))))))

View File

@ -285,9 +285,9 @@
#f))
(test (overlay/align 'middle
'middle
(ellipse 100 50 'solid 'green)
(ellipse 50 100 'solid 'red))
'middle
(ellipse 100 50 'solid 'green)
(ellipse 50 100 'solid 'red))
=>
(make-image
(make-overlay
@ -297,9 +297,9 @@
#f))
(test (overlay/align 'middle
'middle
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
'middle
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
@ -310,9 +310,9 @@
(test (overlay/align 'right
'bottom
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
'bottom
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
@ -322,9 +322,9 @@
#f))
(test (overlay/align 'right
'baseline
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
'baseline
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
@ -413,13 +413,136 @@
#f))
(test (above (ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'blue))
(ellipse 100 50 'solid 'blue))
=>
(above/align 'left
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'blue)))
(test (underlay (ellipse 100 100 'solid 'blue)
(ellipse 120 120 'solid 'red))
=>
(make-image
(make-overlay
(make-translate 0 0 (image-shape (ellipse 120 120 'solid 'red)))
(make-translate 0 0 (image-shape (ellipse 100 100 'solid 'blue))))
(make-bb 120
120
120)
#f))
(test (underlay/xy (ellipse 100 100 'solid 'blue)
0 0
(ellipse 120 120 'solid 'red))
=>
(underlay (ellipse 100 100 'solid 'blue)
(ellipse 120 120 'solid 'red)))
(test (underlay/xy (ellipse 50 100 'solid 'red)
-25 25
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
(make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green)))
(make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))))
(make-bb 100
100
100)
#f))
(test (underlay/xy (ellipse 100 50 'solid 'green)
10 10
(ellipse 50 100 'solid 'red))
=>
(make-image
(make-overlay
(make-translate 10 10 (image-shape (ellipse 50 100 'solid 'red)))
(make-translate 0 0 (image-shape (ellipse 100 50 'solid 'green))))
(make-bb 100
110
110)
#f))
(test (underlay (ellipse 100 50 'solid 'green)
(ellipse 50 100 'solid 'red))
=>
(make-image
(make-overlay
(make-translate 0 0 (image-shape (ellipse 50 100 'solid 'red)))
(make-translate 0 0 (image-shape (ellipse 100 50 'solid 'green))))
(make-bb 100
100
100)
#f))
(test (underlay (ellipse 100 100 'solid 'blue)
(ellipse 120 120 'solid 'red)
(ellipse 140 140 'solid 'green))
=>
(make-image
(make-overlay
(make-translate
0 0
(make-overlay
(make-translate 0 0 (image-shape (ellipse 140 140 'solid 'green)))
(make-translate 0 0 (image-shape (ellipse 120 120 'solid 'red)))))
(make-translate 0 0 (image-shape (ellipse 100 100 'solid 'blue))))
(make-bb 140 140 140)
#f))
(test (underlay/align 'middle
'middle
(ellipse 100 50 'solid 'green)
(ellipse 50 100 'solid 'red))
=>
(make-image
(make-overlay
(make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red)))
(make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green))))
(make-bb 100 100 100)
#f))
(test (underlay/align 'middle
'middle
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
(make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green)))
(make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))))
(make-bb 100 100 100)
#f))
(test (underlay/align 'right
'bottom
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
(make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green)))
(make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red))))
(make-bb 100 100 100)
#f))
(test (underlay/align "right"
"baseline"
(ellipse 50 100 'solid 'red)
(ellipse 100 50 'solid 'green))
=>
(make-image
(make-overlay
(make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green)))
(make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red))))
(make-bb 100 100 100)
#f))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; testing normalization
@ -831,3 +954,26 @@
16)
(check-equal? (image-height (bitmap icons/stop-16x16.png))
16)
(check-equal? (let ()
(define bmp (make-object bitmap% 4 4))
(define mask (make-object bitmap% 4 4))
(define bdc (make-object bitmap-dc% bmp))
(send bdc set-brush "black" 'solid)
(send bdc draw-rectangle 0 0 4 4)
(send bdc set-bitmap mask)
(send bdc set-brush "black" 'solid)
(send bdc clear)
(send bdc draw-rectangle 1 1 1 1)
(send bdc set-bitmap #f)
(let-values ([(bytes w h) (bitmap->bytes bmp mask)])
bytes))
(bytes-append #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0"
#"\0\0\0\0" #"\377\0\0\0" #"\0\0\0\0" #"\0\0\0\0"
#"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0"
#"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0"))
;; ensure no error
(check-equal? (begin (scale 2 (make-object bitmap% 10 10))
(void))
(void))

View File

@ -1,5 +1,13 @@
;; The first three lines of this file were inserted by DrScheme. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname world0-stops) (read-case-sensitive #t) (teachpacks ((lib "universe.ss" "teachpack" "2htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "universe.ss" "teachpack" "2htdp")))))
#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname world0-stops) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
(require 2htdp/universe)
"does big-bang stop when the initial world is already a final world?"
(big-bang 0 (stop-when zero?) (on-tick add1))
"does big bang stop when the initial world is a stop world?"
(big-bang (stop-with 0) (on-tick add1))
(define-struct stop (x))

View File

@ -17,11 +17,15 @@
"private/world.ss"
"private/universe.ss"
"private/launch-many-worlds.ss"
"private/stop.ss"
htdp/error
(rename-in lang/prim (first-order->higher-order f2h)))
(provide (all-from-out "private/image.ss"))
(provide
(rename-out (make-stop-the-world stop-with))) ;; World -> STOP
(provide
launch-many-worlds
;; (launch-many-worlds e1 ... e2)

View File

@ -1,35 +1,12 @@
(module bd-tool mzscheme
(require framework/private/decode)
(decode 05c1dd6edc460c06d057f9226301b2e86c5c23690103a9835c
e53a0f50602852d2ecce8f324379adb7ef3924b6a60aeaf6fb
48dd403909a6d24daf634c984a379d189493609a731ce33ac6
c4a09c04d351935fc79818949360f2d6f2758c0993f6316f56
6c6206a92da91a7a133983683cdf40d91c440a1a36b7aa23fc
abd10d341fbd5bf5306c6e550733332856057d0369740ba555
dfa08c7f18f40da4d12d683ca18c17666690da92aa41d21aa4
806255f4267206d178be814abc5b6872b3d921c94bdc2f2039
52d6b047df4073cbd9664fad863dfa8629e6b5e5bf9f27c624
7abdedebc4cc0c525b5235e4e49e2d4801c5aae84de40ca2f1
7c0365f33f40240554e2dd42939bcd0e495ee27e017d060dab
0a496b9082d53c3c92fac6f8c2a0cfa0615521690d52b09a87
cdd2ba39e30b338374069578b7d0e466b3439297b8079d2f90
c2cca06155a13386791873cc86e7ebcb573c5f5fbe32685855
e80cedf1112479893b24ad410a9ef1cca06155a133867990e4
25ee785a18529819b4f7f69ed4e0ade5ef0c525b52b570d4e4
f0d6f277502a7beb0eed63deacd8abb796ff63907decad3bb4
8f79b362afde5a0ef6b1b7eee33f06a92da91af62d0efb0bef
2d2983d496540dfb1687bde0bd256590da92aa814abc5ba8f6
08474d1e961e8b5d308eddfa8541738e63601cbbf50b28d5cd
7a72ace6410ef756c31eab65068d63b71e521d1eaba7e80662
06a92da91ae4706f1594eaf0583d4537c8e1deea0594937bb6
2005b49a0739dc5b0d7bac96199463118d2039dc5b85bd3b83
b239881454e2dd42939bcd0e4d31b7f582e967dcf7133f52f7
4de3f9277e3591f3d384a785994125de2d34b9d9ec2836465c
ed02496b9002655089770b4d6e363be4706ff582e967dcf713
3f52f74de3895f4de4fc3441413916d108121883865585626c
ed81a78519f4fb686e20695dad333368585528c6d61e787266
66d0f0331be8f7d1dc406ad9dc94999941c3aa8256f320877b
ab618fd53263de625d2dcc5bcadaad82722ca211941934b73a
20877babc8cccc0c7a6c56d19bc81944e3f906d23ee6cd8abd
aee69fedc3adeaab7db8550d474d1e961e8ba1c4bb856a8f70
d4e461e9b1d8054f0b33f3ff))
#lang s-exp framework/private/decode
bVTbjtsgEP2VqatIdlWyadSLtFIv6lOf+wErgZkYthi8gJPN33cAO3GyfonjM2fOXDi49vgy
ao9QGy2g6j3KbQhV+Vc1E9waHkLCZ2C0Oi7fo3Om5EkfWoU9Vg3FJB60RfBOiDMTkp9/Eh8j
1LWEOmDrrAzsh+SR6rej92gjm+CmSQLcEvE7CRGF9c5GBbKBb80VJNEE7Qt/Kih0x0Rf0m+K
9/wfMieesY1Eij0fNlCLURvJBk7ideuMoaB2tgAVN50zX3c0aSXk9nnoqptKRsdocL0YTfqB
Rk2x1boPaQeUNHXbYWQnLaNq4HOzGlWoOxVTOHfQruky2W5A9JmR84kWKDe03CDstvsv+WcR
lZ6fWEmei+1gd5c+xd8fmll88O6oJUI6+l+XhbDkjIJBrfvB+QizJR4T/ERUfH2LswKGp+tu
B8UDfoKj0/IO3N+BZQ8WT7k8O3je4wbCOKDfECvbd3qlrqxCT02mjYoxxnzUFk2aOFGYtiFy
G3W25dJVmZwErvGCbdI1uBhhRdjwnkyRrJYl8BibxU1YnqLU3LhuA9UfPgxn+K19VGSnj/A3
WetdlY4g9bTM6TEE3tHE0/HJu/jc5J3mRVIuGgS8nDwE5U65HtQvo0vbEM5L9AtzTZxYLkWI
ZzLZTJZIE6Jsmit/ZTet4rZD1iq6hPQBuLaS9kafgjDv3UxCJ0Wsm4t2MRKpP+BrpEqP5bHw
A6x6JG/zPw==

View File

@ -14,18 +14,19 @@
(apply p args))))
(define-values (at-read at-read-syntax at-get-info)
(make-meta-reader 'at-exp
"language path"
(lambda (str)
(let ([s (string->symbol
(string-append (bytes->string/latin-1 str)
"/lang/reader"))])
(and (module-path? s) s)))
wrap-reader
wrap-reader
(lambda (proc)
(lambda (key defval)
(case key
[(color-lexer)
(dynamic-require 'syntax-color/scribble-lexer 'scribble-lexer)]
[else (if proc (proc key defval) defval)]))))))
(make-meta-reader
'at-exp
"language path"
(lambda (str)
(let ([s (string->symbol
(string-append (bytes->string/latin-1 str)
"/lang/reader"))])
(and (module-path? s) s)))
wrap-reader
wrap-reader
(lambda (proc)
(lambda (key defval)
(case key
[(color-lexer)
(dynamic-require 'syntax-color/scribble-lexer 'scribble-lexer)]
[else (if proc (proc key defval) defval)]))))))

View File

@ -23,24 +23,24 @@
@title{@bold{Browser}: Simple HTML Rendering}
The @schememodname[browser] library provides the following
procedures and classes for parsing and viewing HTML files. The
@schememodname[browser/htmltext] library provides a simplified
interface for rendering to a subclass of the MrEd @scheme[text%]
class. The @schememodname[browser/external] library provides utilities
for launching an external browser (such as Firefox).
The @schememodname[browser] library provides the following procedures
and classes for parsing and viewing HTML files. The
@schememodname[browser/htmltext] library provides a simplified interface
for rendering to a subclass of the MrEd @scheme[text%] class. The
@schememodname[browser/external] library provides utilities for
launching an external browser (such as Firefox).
@section[#:tag "browser"]{Browser}
@defmodule[browser]
The browser supports basic HTML commands, plus special Scheme
hyperlinks of the form @(litchar "<A MZSCHEME=sexpr>...</A>"). When
the user clicks on such a link, the string @scheme[sexpr] is parsed as
a Scheme program and evaluated. Since @scheme[sexpr] is likely to
contain Scheme strings, and since escape characters are difficult for
people to read, a @litchar{|} character in @scheme[sexpr] is
converted to a @litchar{"} character before it is parsed. Thus,
The browser supports basic HTML commands, plus special Scheme hyperlinks
of the form @litchar{<A MZSCHEME=sexpr>...</A>}. When the user clicks
on such a link, the string @scheme[sexpr] is parsed as a Scheme program
and evaluated. Since @scheme[sexpr] is likely to contain Scheme
strings, and since escape characters are difficult for people to read, a
@litchar{|} character in @scheme[sexpr] is converted to a @litchar{"}
character before it is parsed. Thus,
@verbatim[#:indent 2]{
<A MZSCHEME="|This goes nowhere.|">Nowhere</A>
@ -49,214 +49,211 @@ converted to a @litchar{"} character before it is parsed. Thus,
creates a ``Nowhere'' hyperlink, which executes the Scheme program
@schemeblock[
"This goes nowhere."
"This goes nowhere."
]
The value of that program is a string. When a Scheme hyperlink returns
a string, it is parsed as a new HTML document. Thus, where the use
The value of that program is a string. When a Scheme hyperlink returns
a string, it is parsed as a new HTML document. Thus, where the use
clicks on ``Nowhere,'' the result is a new page that says ``This goes
nowhere.''
The browser also treats comment forms containing @(litchar "MZSCHEME=sexpr")
specially. Whereas the @(litchar "<A MZSCHEME=sexpr>...</A>") form executes the
expression when the user clicks, the @(litchar "MZSCHEME") expression in a comment
is executed immediately during HTML rendering. If the result is a
string, the comment is replaced in the input HTML stream with the
content of the string. Thus,
The browser also treats comment forms containing
@litchar{MZSCHEME=sexpr} specially. Whereas the
@litchar{<A MZSCHEME=sexpr>...</A>} form executes the expression when
the user clicks, the @litchar{MZSCHEME} expression in a comment is
executed immediately during HTML rendering. If the result is a string,
the comment is replaced in the input HTML stream with the content of the
string. Thus,
@verbatim[#:indent 2]{
<!-- MZSCHEME="(format |<B>Here</B>: ~a| (current-directory))" -->
}
inserts the path of the current working directory into the containing
document (and ``Here'' is boldfaced). If the result is a snip instead
of a string, it replaces the comment in the document. Other types of
document (and ``Here'' is boldfaced). If the result is a snip instead
of a string, it replaces the comment in the document. Other types of
return values are ignored.
If the html file is being accessed as a @(litchar "file:") url, the
If the html file is being accessed as a @litchar{file:} url, the
@scheme[current-load-relative-directory] parameter is set to the
directory during the evaluation of the mzscheme code (in both
examples). The Scheme code is executed through @scheme[eval].
examples). The Scheme code is executed through @scheme[eval].
The @(litchar "MZSCHEME") forms are disabled unless the web page is a
@(litchar "file:") url that points into the @scheme[doc] collection.
The @litchar{MZSCHEME} forms are disabled unless the web page is a
@litchar{file:} url that points into the @scheme[doc] collection.
@defproc[(open-url [url (or/c url? string? input-port?)]) (is-a?/c hyper-frame%)]{
Opens the given url
in a vanilla browser frame and returns
the frame. The frame is an instance of
@scheme[hyper-frame%].
Opens the given url in a vanilla browser frame and returns the
frame. The frame is an instance of @scheme[hyper-frame%].
}
@defboolparam[html-img-ok ok?]{
A parameter that determines whether the browser attempts to
download and render images.
A parameter that determines whether the browser attempts to download
and render images.
}
@defboolparam[html-eval-ok ok?]{
A parameter that determines whether @(litchar "MZSCHEME=")
tags are evaluated.
A parameter that determines whether @litchar{MZSCHEME=} tags are
evaluated.
}
@; ----------------------------------------------------------------------
@defmixin[hyper-frame-mixin (frame%) ()]{
@defconstructor/auto-super[([url (or/c url? string? input-port?)])]{
Shows the frame and visits @scheme[url].
}
@defconstructor/auto-super[([url (or/c url? string? input-port?)])]{
Shows the frame and visits @scheme[url].
}
@defmethod[(get-hyper-panel%) (subclass?/c panel%)]{
Returns the class that is instantiated when the frame is created.
Must be a panel with hyper-panel-mixin mixed in. Defaults to
just returning @scheme[hyper-panel%].
}
@defmethod[(get-hyper-panel%) (subclass?/c panel%)]{
Returns the class that is instantiated when the frame is created.
Must be a panel with hyper-panel-mixin mixed in. Defaults to just
returning @scheme[hyper-panel%].
}
@defmethod[(get-hyper-panel) (is-a?/c panel%)]{
Returns the hyper panel in this frame.
}
@defmethod[(get-hyper-panel) (is-a?/c panel%)]{
Returns the hyper panel in this frame.
}
}
@; ----------------------------------------------------------------------
@defclass[hyper-no-show-frame% (hyper-frame-mixin (frame:status-line-mixin frame:basic%)) ()]
@defclass[hyper-no-show-frame%
(hyper-frame-mixin (frame:status-line-mixin frame:basic%))
()]
@; ----------------------------------------------------------------------
@defmixin[hyper-no-show-frame-mixin (frame%) ()]{
The same as the @scheme[hyper-frame-mixin], except that it
doesn't show the frame and the initialization arguments
are unchanged.
The same as the @scheme[hyper-frame-mixin], except that it doesn't
show the frame and the initialization arguments are unchanged.
}
@; ----------------------------------------------------------------------
@defclass[hyper-frame% (hyper-no-show-frame-mixin (frame:status-line-mixin frame:basic%)) ()]
@defclass[hyper-frame%
(hyper-no-show-frame-mixin (frame:status-line-mixin frame:basic%))
()]
@; ----------------------------------------------------------------------
@defmixin[hyper-text-mixin (text%) ()]{
An instance of a @scheme[hyper-text-mixin]-extended class
should be displayed only in an instance of a class created
with @scheme[hyper-canvas-mixin].
An instance of a @scheme[hyper-text-mixin]-extended class should be
displayed only in an instance of a class created with
@scheme[hyper-canvas-mixin].
@defconstructor/auto-super[([url (or/c url? string? input-port?)]
[status-frame (or/c (is-a?/c top-level-window<%>) false/c)]
[post-data (or/c false/c bytes?)])]{
The @scheme[url] is loaded into the @scheme[text%] object
(using the @method[hyper-text-mixin reload] method), a
top-level window for status messages and dialogs, a progress
procedure used as for @scheme[get-url], and either @scheme[#f]
or a post string to be sent to a web server (technically
changing the GET to a POST).
@defconstructor/auto-super[([url (or/c url? string? input-port?)]
[status-frame
(or/c (is-a?/c top-level-window<%>) false/c)]
[post-data (or/c false/c bytes?)])]{
The @scheme[url] is loaded into the @scheme[text%] object (using the
@method[hyper-text-mixin reload] method), a top-level window for
status messages and dialogs, a progress procedure used as for
@scheme[get-url], and either @scheme[#f] or a post string to be sent
to a web server (technically changing the GET to a POST).
Sets the autowrap-bitmap to @scheme[#f].
}
Sets the autowrap-bitmap to @scheme[#f].
}
@defmethod[(map-shift-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[shift-style style<%>])
void?]{
Maps the given style over the given range.
}
@defmethod[(map-shift-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[shift-style style<%>])
void?]{
Maps the given style over the given range.
}
@defmethod[(make-link-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?])
void?]{
Changes the style for the given range to the link style.
}
@defmethod[(make-link-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?])
void?]{
Changes the style for the given range to the link style.
}
@defmethod[(get-url) (or/c url? string? input-port? false/c)]{
Returns the URL displayed by the editor, or @scheme[#f] if there
is none.
}
@defmethod[(get-url) (or/c url? string? input-port? false/c)]{
Returns the URL displayed by the editor, or @scheme[#f] if there is
none.
}
@defmethod[(get-title) string?]{
Gets the page's title.
}
@defmethod[(get-title) string?]{
Gets the page's title.
}
@defmethod[(set-title [str string?]) void?]{
Sets the page's title.
}
@defmethod[(set-title [str string?]) void?]{
Sets the page's title.
}
@defmethod[(hyper-delta) style-delta%]{
Override this method to set the link style.
}
@defmethod[(hyper-delta) style-delta%]{
Override this method to set the link style.
}
@defmethod[(add-tag [name string?] [pos exact-nonnegative-integer?]) void?]{
Installs a tag.
}
@defmethod[(add-tag [name string?] [pos exact-nonnegative-integer?]) void?]{
Installs a tag.
}
@defmethod[(find-tag [name/number (or/c string? exact-nonnegative-integer?)])
(or/c exact-nonnegative-integer? false/c)]{
Finds the location of a tag in the buffer (where tags
are installed in HTML with @(litchar "<A
NAME=\"name\">")) and returns its position. If
@scheme[name] is a number, the number is returned
(assumed to be an offset rather than a
tag). Otherwise, if the tag is not found, @scheme[#f]
is returned.
}
@defmethod[(find-tag [name/number (or/c string? exact-nonnegative-integer?)])
(or/c exact-nonnegative-integer? false/c)]{
Finds the location of a tag in the buffer (where tags are installed
in HTML with @litchar{<A NAME="name">}) and returns its position.
If @scheme[name] is a number, the number is returned (assumed to be
an offset rather than a tag). Otherwise, if the tag is not found,
@scheme[#f] is returned.
}
@defmethod[(remove-tag [name string?]) void?]{
Removes a tag.
}
@defmethod[(remove-tag [name string?]) void?]{
Removes a tag.
}
@defmethod[(post-url [url (or/c string? url?)]
[post-data-bytes (or/c bytes? false/c) #f]) void?]{
Follows the link, optionally with the given post data.
}
@defmethod[(post-url [url (or/c string? url?)]
[post-data-bytes (or/c bytes? false/c) #f]) void?]{
Follows the link, optionally with the given post data.
}
@defmethod[(add-link [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[url (or/c url? string?)])
void?]{
Installs a hyperlink.
}
@defmethod[(add-link [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[url (or/c url? string?)])
void?]{
Installs a hyperlink.
}
@defmethod[(add-scheme-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[scheme-expr string?])
void?]{
Installs a Scheme evaluation hyperlink.
}
@defmethod[(add-scheme-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[scheme-expr string?])
void?]{
Installs a Scheme evaluation hyperlink.
}
@defmethod[(add-thunk-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[thunk (-> any)])
void?]{
Installs a thunk-based hyperlink.
}
@defmethod[(add-thunk-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[thunk (-> any)])
void?]{
Installs a thunk-based hyperlink.
}
@defmethod[(eval-scheme-string [str string?]) any]{
Called to handle the @(litchar "<A MZSCHEME=\"expr\">...</A>")
tag and @(litchar "<! MZSCHEME=\"expr\">") comments (see above).
Evaluates the string; if the result is a string,
it is opened as an HTML page.
}
@defmethod[(eval-scheme-string [str string?]) any]{
Called to handle the @litchar{<A MZSCHEME="expr">...</A>} tag and
@litchar{<! MZSCHEME="expr">} comments (see above). Evaluates the
string; if the result is a string, it is opened as an HTML page.
}
@defmethod[(reload) void?]{
Reloads the current page.
@defmethod[(reload) void?]{
Reloads the current page.
The text defaultly uses the basic style named
@scheme["Html Standard"] in the editor (if it exists).
}
The text defaultly uses the basic style named
@scheme["Html Standard"] in the editor (if it exists).
}
@defmethod[(remap-url [url (or/c url? string?)]) (or/c url? string?)]{
When visiting a new page, this method is called to remap
the url. The remapped url is used in place of the
original url. If this method returns @scheme[#f], the page doesn't
go anywhere.
@defmethod[(remap-url [url (or/c url? string?)]) (or/c url? string?)]{
When visiting a new page, this method is called to remap the url.
The remapped url is used in place of the original url. If this
method returns @scheme[#f], the page doesn't go anywhere.
This method may be killed (if the user clicks the
``stop'' button).
}
@defmethod[(get-hyper-keymap) (is-a?/c keymap%)]{
Returns a keymap suitable for frame-level handling of events to
redirect page-up, @|etc| to the browser canvas.
}
This method may be killed (if the user clicks the ``stop'' button).
}
@defmethod[(get-hyper-keymap) (is-a?/c keymap%)]{
Returns a keymap suitable for frame-level handling of events to
redirect page-up, @|etc| to the browser canvas.
}
}
@ -264,8 +261,8 @@ The @(litchar "MZSCHEME") forms are disabled unless the web page is a
@defclass[hyper-text% (hyper-text-mixin text:keymap%) ()]{
Extends the @scheme[text:keymap%] class to support standard
key bindings in the browser window.
Extends the @scheme[text:keymap%] class to support standard key
bindings in the browser window.
}
@ -273,135 +270,130 @@ The @(litchar "MZSCHEME") forms are disabled unless the web page is a
@defmixin[hyper-canvas-mixin (editor-canvas%) ()]{
A @scheme[hyper-can-mixin]-extended canvas's parent should be
an instance of a class derived with
@scheme[hyper-panel-mixin].
A @scheme[hyper-can-mixin]-extended canvas's parent should be an
instance of a class derived with @scheme[hyper-panel-mixin].
@defconstructor/auto-super[()]{
}
@defconstructor/auto-super[()]{
}
@defmethod[(get-editor%) (subclass?/c text%)]{
@defmethod[(get-editor%) (subclass?/c text%)]{
Returns the class used to implement the editor in the browser
window. It should be derived from @scheme[hyper-text%] and
should pass on the initialization arguments to
@scheme[hyper-text%].
Returns the class used to implement the editor in the browser
window. It should be derived from @scheme[hyper-text%] and should
pass on the initialization arguments to @scheme[hyper-text%].
The dynamic extent of the initialization of this
editor is called on a thread that may be killed (via a
custodian shutdown). In that case, the editor in the browser's
editor-canvas may not be an instance of this class.
}
The dynamic extent of the initialization of this editor is called on
a thread that may be killed (via a custodian shutdown). In that
case, the editor in the browser's editor-canvas may not be an
instance of this class.
}
@defmethod[(current-page) any/c]{
Returns a representation of the currently displayed page, which
includes a particular editor and a visible range within the
editor.
}
@defmethod[(current-page) any/c]{
Returns a representation of the currently displayed page, which
includes a particular editor and a visible range within the editor.
}
@defmethod[(goto-url [url (or/c url? string?)]
[relative-to-url (or/c url? string? false/c)]
[progress-proc (boolean? . -> . any) void]
[post-data (or/c bytes? false/c) #f])
void?]{
Changes to the given url, loading it by calling the @scheme[make-editor]
method. If @scheme[relative-to-url] is not @scheme[#f], it must be
a URL for resolving @scheme[url] as a relative URL.
@scheme[url] may also be a port, in which case,
@scheme[relative-to-url] must be @scheme[#f].
@defmethod[(goto-url [url (or/c url? string?)]
[relative-to-url (or/c url? string? false/c)]
[progress-proc (boolean? . -> . any) void]
[post-data (or/c bytes? false/c) #f])
void?]{
Changes to the given url, loading it by calling the
@scheme[make-editor] method. If @scheme[relative-to-url] is not
@scheme[#f], it must be a URL for resolving @scheme[url] as a
relative URL. @scheme[url] may also be a port, in which case,
@scheme[relative-to-url] must be @scheme[#f].
The @scheme[progress-proc] procedure is called with a boolean at the
point where the URL has been resolved and enough progress has
been made to dismiss any message that the URL is being
resolved. The procedure is called with @scheme[#t] if the URL will be
loaded into a browser window, @scheme[#f] otherwise (e.g., the user will
save the URL content to a file).
The @scheme[progress-proc] procedure is called with a boolean at the
point where the URL has been resolved and enough progress has been
made to dismiss any message that the URL is being resolved. The
procedure is called with @scheme[#t] if the URL will be loaded into
a browser window, @scheme[#f] otherwise (e.g., the user will save
the URL content to a file).
If @scheme[post-data-bytes] is a byte string instead of false, the URL
GET is changed to a POST with the given data.
}
If @scheme[post-data-bytes] is a byte string instead of false, the
URL GET is changed to a POST with the given data.
}
@defmethod[(set-page [page any/c] [notify? any/c]) void?]{
Changes to the given page. If @scheme[notify?] is not @scheme[#f],
the canvas's parent is notified about the change by calling its
@scheme[leaving-page] method.
}
@defmethod[(set-page [page any/c] [notify? any/c]) void?]{
Changes to the given page. If @scheme[notify?] is not @scheme[#f],
the canvas's parent is notified about the change by calling its
@scheme[leaving-page] method.
}
@defmethod[(after-set-page) void?]{
Called during @scheme[set-page]. Defaultly does nothing.
}
@defmethod[(after-set-page) void?]{
Called during @scheme[set-page]. Defaultly does nothing.
}
}
@; ----------------------------------------------------------------------
@defmixin[hyper-panel-mixin (area-container<%>) ()]{
@defconstructor/auto-super[([info-line? any/c])]{
Creates controls and a hyper text canvas. The
controls permit a user to move back and forth in the hypertext
history.
The @scheme[info-line?] argument indicates whether the browser
should contain a line to display special @(litchar "DOCNOTE")
tags in a page. Such tags are used primarily by the PLT
documentation.}
@defmethod[(make-canvas [container (is-a?/c area-container<%>)]) void?]{
Creates the panel's hypertext canvas, an instance of a class
derived using @scheme[hyper-canvas-mixin]. This
method is called during initialization.
}
@defconstructor/auto-super[([info-line? any/c])]{
Creates controls and a hyper text canvas. The controls permit a
user to move back and forth in the hypertext history.
@defmethod[(get-canvas%) (subclass?/c editor-canvas%)]{
Returns the class instantiated by make-canvas. It must be derived from
@scheme[hyper-canvas-mixin].
}
The @scheme[info-line?] argument indicates whether the browser
should contain a line to display special @litchar{DOCNOTE} tags in a
page. Such tags are used primarily by the PLT documentation.
}
@defmethod[(make-control-bar-panel [container (is-a?/c area-container<%>)])
any/c]{
Creates the panel's sub-container for the control bar containing
the navigation buttons. If @scheme[#f] is returned, the panel will
have no control bar. The default method instantiates
@scheme[horizontal-panel%].
}
@defmethod[(make-canvas [container (is-a?/c area-container<%>)]) void?]{
Creates the panel's hypertext canvas, an instance of a class derived
using @scheme[hyper-canvas-mixin]. This method is called during
initialization.
}
@defmethod[(rewind) void?]{
Goes back one page, if possible.
}
@defmethod[(get-canvas%) (subclass?/c editor-canvas%)]{
Returns the class instantiated by make-canvas. It must be derived
from @scheme[hyper-canvas-mixin].
}
@defmethod[(forward) void?]{
Goes forward one page, if possible.
}
@defmethod[(make-control-bar-panel [container (is-a?/c area-container<%>)])
any/c]{
Creates the panel's sub-container for the control bar containing the
navigation buttons. If @scheme[#f] is returned, the panel will have
no control bar. The default method instantiates
@scheme[horizontal-panel%].
}
@defmethod[(get-canvas) (is-a?/c editor-canvas%)]{
Gets the hypertext canvas.
}
@defmethod[(rewind) void?]{
Goes back one page, if possible.
}
@defmethod[(on-navigate) void?]{
Callback that is invoked any time the displayed hypertext page
changes (either by clicking on a link in the canvas or by
@scheme[rewind] or @scheme[forward] calls).
}
@defmethod[(forward) void?]{
Goes forward one page, if possible.
}
@defmethod[(leaving-page [page any/c] [new-page any/c])
any]{
This method is called by the hypertext canvas to notify the
panel that the hypertext page changed. The @scheme[page] is @scheme[#f]
if @scheme[new-page] is the first page for the canvas. See also
@scheme[page->editor].
}
@defmethod[(get-canvas) (is-a?/c editor-canvas%)]{
Gets the hypertext canvas.
}
@defmethod[(filter-notes [notes (listof string?)])
(listof string?)]{
Given the notes from a page as a list of strings (where
each string is a note), returns a single string to print
above the page.
}
@defmethod[(on-navigate) void?]{
Callback that is invoked any time the displayed hypertext page
changes (either by clicking on a link in the canvas or by
@scheme[rewind] or @scheme[forward] calls).
}
@defmethod[(reload) void?]{
Reloads the currently visible page by calling the @scheme[reload]
method of the currently displayed hyper-text.
}
@defmethod[(leaving-page [page any/c] [new-page any/c])
any]{
This method is called by the hypertext canvas to notify the panel
that the hypertext page changed. The @scheme[page] is @scheme[#f]
if @scheme[new-page] is the first page for the canvas. See also
@scheme[page->editor].
}
@defmethod[(filter-notes [notes (listof string?)])
(listof string?)]{
Given the notes from a page as a list of strings (where each string
is a note), returns a single string to print above the page.
}
@defmethod[(reload) void?]{
Reloads the currently visible page by calling the @scheme[reload]
method of the currently displayed hyper-text.
}
}
@; ----------------------------------------------------------------------
@ -411,46 +403,43 @@ The @(litchar "MZSCHEME") forms are disabled unless the web page is a
@; ----------------------------------------------------------------------
@defproc[(editor->page [editor (is-a?/c text%)]) any/c]{
Creates a page record for the given editor,
suitable for use with the @scheme[set-page] method of
@scheme[hyper-canvas-mixin].
Creates a page record for the given editor, suitable for use with the
@scheme[set-page] method of @scheme[hyper-canvas-mixin].
}
@defproc[(page->editor [page any/c]) (is-a?/c text%)]{
Extracts the editor from a page record.
Extracts the editor from a page record.
}
@defparam[bullet-size n exact-nonnegative-integer?]{
Parameter controlling the point size of a
bullet.
Parameter controlling the point size of a bullet.
}
@defclass[image-map-snip% snip% ()]{
Instances of this class behave like @scheme[image-snip%] objects,
except they have a @(litchar "<map> ... </map>") associated with them and
when clicking on them (in the map) they will cause their
init arg text to follow the corresponding link.
Instances of this class behave like @scheme[image-snip%] objects,
except they have a @litchar{<map> ... </map>} associated with them and
when clicking on them (in the map) they will cause their init arg text
to follow the corresponding link.
@defconstructor[([html-text (is-a?/c html-text<%>)])]{
}
@defconstructor[([html-text (is-a?/c html-text<%>)])]{
}
@defmethod[(set-key [key string?]) void?]{
Sets the key for the image map (eg, "#key").
}
@defmethod[(set-key [key string?]) void?]{
Sets the key for the image map (eg, @scheme["#key"]).
}
@defmethod[(get-key) string?]{
Returns the current key.
}
@defmethod[(get-key) string?]{
Returns the current key.
}
@defmethod[(add-area [shape string?]
[region (listof number?)]
[href string?])
void?]{
Registers the shape named by @scheme[shape] whose
coordinates are specified by @scheme[region] to go to
@scheme[href] when that region of the image
is clicked on.
}
@defmethod[(add-area [shape string?]
[region (listof number?)]
[href string?])
void?]{
Registers the shape named by @scheme[shape] whose coordinates are
specified by @scheme[region] to go to @scheme[href] when that region
of the image is clicked on.
}
}
@; ----------------------------------------------------------------------
@ -460,9 +449,9 @@ The @(litchar "MZSCHEME") forms are disabled unless the web page is a
@defmodule[browser/browser-unit]
@defthing[browser@ unit?]{
Imports @scheme[mred^], @scheme[tcp^], and @scheme[url^], and exports
@scheme[browser^].}
Imports @scheme[mred^], @scheme[tcp^], and @scheme[url^], and exports
@scheme[browser^].
}
@; ----------------------------------------------------------------------
@ -471,9 +460,8 @@ Imports @scheme[mred^], @scheme[tcp^], and @scheme[url^], and exports
@defmodule[browser/browser-sig]
@defsignature[browser^ ()]{
Includes all of the bindings of the @schememodname[browser]
library.}
Includes all of the bindings of the @schememodname[browser] library.
}
@; ----------------------------------------------------------------------
@ -483,75 +471,73 @@ library.}
@definterface[html-text<%> (text%)]{
@defmethod[(get-url) (or/c url? string? false/c)]{
Returns a base URL used for building
relative URLs, or @scheme[#f] if no base is available.
}
@defmethod[(get-url) (or/c url? string? false/c)]{
Returns a base URL used for building relative URLs, or @scheme[#f]
if no base is available.
}
@defmethod[(set-title [str string?]) void?]{
Registers the title @scheme[str]
for the rendered page.
}
@defmethod[(set-title [str string?]) void?]{
Registers the title @scheme[str] for the rendered page.
}
@defmethod[(add-link [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[url (or/c url? string?)])
void?]{
Registers a hyperlink for the given region in rendered page.
}
@defmethod[(add-link [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[url (or/c url? string?)])
void?]{
Registers a hyperlink for the given region in rendered page.
}
@defmethod[(add-tag [name string?] [pos exact-nonnegative-integer?]) void?]{
Installs a tag.
}
@defmethod[(add-tag [name string?] [pos exact-nonnegative-integer?]) void?]{
Installs a tag.
}
@defmethod[(make-link-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?])
void?]{
Changes the style for the given range to the link style.
}
@defmethod[(make-link-style [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?])
void?]{
Changes the style for the given range to the link style.
}
@defmethod[(add-scheme-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[scheme-expr string?])
void?]{
Installs a Scheme evaluation hyperlink.
}
@defmethod[(add-scheme-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[scheme-expr string?])
void?]{
Installs a Scheme evaluation hyperlink.
}
@defmethod[(add-thunk-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[thunk (-> any)])
void?]{
Installs a thunk-based hyperlink.
}
@defmethod[(add-thunk-callback [start exact-nonnegative-integer?]
[end exact-nonnegative-integer?]
[thunk (-> any)])
void?]{
Installs a thunk-based hyperlink.
}
@defmethod[(post-url [url (or/c string? url?)]
[post-data-bytes (or/c bytes? false/c) #f]) void?]{
Follows the link, optionally with the given post data.
}
@defmethod[(post-url [url (or/c string? url?)]
[post-data-bytes (or/c bytes? false/c) #f]) void?]{
Follows the link, optionally with the given post data.
}
}
@defmixin[html-text-mixin (text%) ()]{
Extends the given @scheme[text%] class with implementations of the
@scheme[html-text<%>] methods. Hyperlinks are attached to clickbacks
that use @net-send-url from @schememodname[net/sendurl].
Extends the given @scheme[text%] class with implementations of the
@scheme[html-text<%>] methods. Hyperlinks are attached to clickbacks
that use @net-send-url from @schememodname[net/sendurl].
}
@defproc[(render-html-to-text [in input-port?]
@defproc[(render-html-to-text [in input-port?]
[dest (is-a? html-text<%>)]
[load-img? any/c]
[load-img? any/c]
[eval-mz? any/c])
void?]{
Reads HTML from @scheme[in] and renders it to @scheme[dest]. If
@scheme[load-img?] is @scheme[#f], then images are rendered as Xed-out
boxes. If @scheme[eval-mz?] is @scheme[#f], then @litchar{MZSCHEME}
hyperlink expressions and comments are not evaluated.
Reads HTML from @scheme[in] and renders it to @scheme[dest].
If @scheme[load-img?] is @scheme[#f], then images are rendered
as Xed-out boxes. If @scheme[eval-mz?] is @scheme[#f], then
@litchar{MZSCHEME} hyperlink expressions and comments are not
evaluated.
Uses the style named @scheme["Html Standard"] in the editor's
style-list (if it exists) for all of the inserted text's
default style.}
Uses the style named @scheme["Html Standard"] in the editor's
style-list (if it exists) for all of the inserted text's default
style.
}
@; ----------------------------------------------------------------------
@ -560,32 +546,33 @@ library.}
@defmodule[browser/external]
@defproc[(send-url [str null] [separate-window? void #t]) null]{
Like @net-send-url from @scheme[net/sendurl] , but under Unix,
the user is prompted for a browser to use if none is recorded
in the preferences file.
Like @net-send-url from @scheme[net/sendurl], but under Unix, the user
is prompted for a browser to use if none is recorded in the
preferences file.
}
@defproc[(browser-preference? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a valid browser preference.
Returns @scheme[#t] if @scheme[v] is a valid browser preference.
}
@defproc[(update-browser-preference [url (or/c string? false/c)]) void?]{
Under Unix, prompts the user for a browser preference and records
the user choice as a framework preference (even if one is already
recorded). If @scheme[url] is not @scheme[#f], it is used in the
dialog to explain which URL is to be opened; if it is @scheme[#f],
the @scheme['internal] will be one of the options for the user.
Under Unix, prompts the user for a browser preference and records the
user choice as a framework preference (even if one is already
recorded). If @scheme[url] is not @scheme[#f], it is used in the
dialog to explain which URL is to be opened; if it is @scheme[#f], the
@scheme['internal] will be one of the options for the user.
}
@defproc[(install-help-browser-preference-panel) void?]{
Installs a framework preference panel for ``Browser'' options.
Installs a framework preference panel for ``Browser'' options.
}
@defproc[(add-to-browser-prefs-panel [proc ((is-a?/c panel%) . -> . any)]) void?]{
The @scheme[proc] is called when the ``Browser'' panel is constructed for
preferences. The supplied argument is the panel, so @scheme[proc] can add
additional option controls. If the panel is already created, @scheme[proc]
is called immediately.
@defproc[(add-to-browser-prefs-panel [proc ((is-a?/c panel%) . -> . any)])
void?]{
The @scheme[proc] is called when the ``Browser'' panel is constructed
for preferences. The supplied argument is the panel, so @scheme[proc]
can add additional option controls. If the panel is already created,
@scheme[proc] is called immediately.
}
@; ----------------------------------------------------------------------
@ -595,7 +582,6 @@ library.}
@defmodule[browser/tool]
@defthing[tool@ unit?]{
A unit that implements a DrScheme tool to add the ``Browser''
preference panel.
}

View File

@ -321,13 +321,15 @@
list list* vector vector-immutable box))]
[(3) (memq (car a) '(eq? = <= < >= >
bitwise-bit-set? char=?
+ - * / quotient remainder min max bitwise-and bitwise-ior
+ - * / quotient remainder min max bitwise-and bitwise-ior bitwise-xor
arithmetic-shift vector-ref string-ref bytes-ref
set-mcar! set-mcdr! cons mcons
list list* vector vector-immutable))]
[(4) (memq (car a) '(vector-set! string-set! bytes-set!
list list* vector vector-immutable))]
[else (memq (car a) '(list list* vector vector-immutable))]))
list list* vector vector-immutable
+ - * / min max bitwise-and bitwise-ior bitwise-xor))]
[else (memq (car a) '(list list* vector vector-immutable
+ - * / min max bitwise-and bitwise-ior bitwise-xor))]))
(cons '#%in a)
a))

View File

@ -19,5 +19,5 @@
procedures
(all-from-except assignments: deinprogramm/DMdA procedures
quote
symbol?))
symbol? string->symbol symbol->string))

View File

@ -18,5 +18,5 @@
quote
make-pair pair? first rest
length map for-each reverse append list list-ref fold
symbol?
symbol? string->symbol symbol->string
apply))

View File

@ -17,5 +17,5 @@
quote eq? equal?
set!
define-record-procedures-2
symbol?
symbol? string->symbol symbol->string
apply))

View File

@ -316,7 +316,9 @@
(symbol? (%a -> boolean)
"feststellen, ob ein Wert ein Symbol ist")
(symbol->string (symbol -> string)
"Symbol in Zeichenkette umwandeln"))
"Symbol in Zeichenkette umwandeln")
(string->symbol (string -> symbol)
"Zeichenkette in Symbol umwandeln"))
("Verschiedenes"
(equal? (%a %b -> boolean)

View File

@ -341,7 +341,7 @@ Dieser Testfall überprüft experimentell, ob die @tech{Eigenschaft}
@emph{Wichtig:} @scheme[check-property] funktioniert nur für
Eigenschaften, bei denen aus den Verträgen sinnvoll Werte generiert
werden können. Dies ist für die meisten eingebauten Verträge der
Fall, aber nicht für Verträge, die mit @scheme[predicate],
Fall, aber nicht für Vertragsvariablen und Verträge, die mit @scheme[predicate],
@scheme[property] oder @scheme[define-record-procedures] definiert
wurden. In diesen Fällen erzeugt @scheme[check-property] eine Fehlermeldung.
}

View File

@ -88,20 +88,20 @@ Die folgenden Prozeduren erzeugen Bilder mit einfachen geometrischen Formen:
@defthing[ellipse (natural natural mode image-color -> image)]{
Der Aufruf @scheme[(ellipse w h m c)]
erzeugt eine Ellipse mit Breite @scheme[w] und Höhe @scheme[h], gefüllt mit Modus
@scheme[m] uns in Farbe @scheme[c].}
@scheme[m] und in Farbe @scheme[c].}
@defthing[triangle (integer mode image-color -> image)]{
Der Aufruf @scheme[(triangle s m c)]
erzeugt ein nach oben zeigendes gleichseitiges Dreieck, wobei
@scheme[s] die Seitenlänge angibt, gefüllt mit Modus
@scheme[m] uns in Farbe @scheme[c].}
@scheme[m] und in Farbe @scheme[c].}
@defthing[line (natural natural number number number number image-color -> image)]{
Der Aufruf @scheme[(line w h sx sy ex ey c)]
erzeugt ein Bild mit einer farbigen Strecke, wobei @scheme[w] die Breite und @scheme[h] die Höhe des Bilds,
sowie @scheme[sx] die X- und @scheme[sx] die Y-Koordinate des Anfangspunkts und
@scheme[ex] die X- und @scheme[ey] die Y-Koordinate des Endpunkts angeben, gefüllt mit Modus
@scheme[m] uns in Farbe @scheme[c].}
@scheme[m] und in Farbe @scheme[c].}
@defthing[text (string natural image-color -> image)]{
Der Aufruf @scheme[(text s f c)]

View File

@ -27,6 +27,18 @@
(define basics-mixin
(mixin (frame:standard-menus<%>) (basics<%>)
(define/override (on-subwindow-char receiver event)
(let ([user-key? (send (keymap:get-user)
handle-key-event
(if (is-a? receiver editor-canvas%)
(send receiver get-editor)
receiver)
event)])
;; (printf "user-key? ~s\n" user-key?) returns #t for key release events -- is this a problem? (we'll find out!)
(or user-key?
(super on-subwindow-char receiver event))))
(inherit get-edit-target-window get-edit-target-object get-menu-bar)
(define/private (get-menu-bindings)
(let ([name-ht (make-hasheq)])

View File

@ -316,6 +316,8 @@
(let loop ([sexp full-sexp])
(match sexp
[`((#%module-begin ,body ...))
(loop body)]
[`((provide/doc (,x ,name ,ctc ,other ...) ...) ,rest ...)
#`(let #,(map (λ (name ctc)
(with-syntax ([name (datum->syntax #'tool-name name)]
@ -331,7 +333,7 @@
[`(,a . ,b)
(loop b)]
[`()
(error 'tcl.ss "did not find provide/doc" full-sexp)])))]))
(error 'tcl.ss "did not find provide/doc: ~a" full-sexp)])))]))
;; invoke-tool : unit/sig string -> (values (-> void) (-> void))
;; invokes the tools and returns the two phase thunks.

View File

@ -4,7 +4,7 @@
scheme/list
(for-label eopl/eopl
scheme/contract
(only-in scheme printf pretty-print)))
(only-in scheme printf pretty-print delay force)))
@(define-syntax-rule (def-mz id)
(begin

View File

@ -1,5 +1,4 @@
#reader scribble/reader
#lang scheme/base
#lang at-exp scheme/base
(require string-constants scheme/gui/base
scheme/contract scheme/class)

View File

@ -1,40 +1,32 @@
#lang scheme/base
(require "decode.ss")
(decode
\5d8f4
\10ec22010
\45aff297b02
\0 \69d544
\5da867
\299da9
\360a3
\5404db
\cbde0b
\4b571f
\7798f6
\13ecaf
\2b5f75
\0cf30bc
\7a62b8d0
\194bcdfb
\023787789
\f02\5b091a
\8ab \8eb3d4
\3a9 \02e040
\3ac \307a74
\ca8 \495944
\6e0 \74fd1
\9ce5 \d88e21
\b04 \f66c25
\a97f \b8d27a
\813 \be13c6
\0d3e \dd50a2
\86d3 \3f5ede
\174a \3235ad9
\ecb40 \2aecb1
\ad56 \76292fb
\6aeb0 \39ae75f
\8f335 \ea955
\e7e \2c7
#lang s-exp framework/private/decode
||\6||\8||\7||\4||\3||\d||\e||\f||\c||\0||\1)
XY9BD
sIgEEWv
8pfMgqRV
E3Whn
qXtT
GOjg
AE08
fYWp
62Nu
897D
PMxjx
heAwtc
7G3Lzfs
CN4 d0m
4K0G giGp
R+8w JgC4
MA0w rvkk
XCTR 5GkC
56T Peux
e8Yo PtsJ
E5X7 jWeY
E74T 1gWf
ryiR 4OjH
y/tK Waem
1XMZ aIU9
ttXK LuXV
1hU2 x7WO
f75G vdLLj
9Xuc CD6A
\\\\ A==

View File

@ -1,43 +1,19 @@
#lang scheme/base
(require (for-syntax mzlib/inflate
scheme/base))
(require (for-syntax scheme/base file/gunzip net/base64))
(provide (except-out (all-from-out scheme/base) #%module-begin)
(rename-out [module-begin #%module-begin]))
(provide decode)
(define-syntax (decode stx)
(define-syntax (module-begin stx)
(syntax-case stx ()
[(_ arg ...)
(andmap identifier? (syntax->list (syntax (arg ...))))
(let ()
(define (decode-sexp str)
(let* ([loc
(let loop ([chars (string->list str)])
(cond
[(null? chars) '()]
[(null? (cdr chars)) (error 'to-sexp "missing digit somewhere")]
[else (let ([fst (to-digit (car chars))]
[snd (to-digit (cadr chars))])
(cons
(+ (* fst 16) snd)
(loop (cddr chars))))]))])
(let-values ([(p-in p-out) (make-pipe)])
(inflate (open-input-bytes (apply bytes loc)) p-out)
(read p-in))))
(define (to-digit char)
(cond
[(char<=? #\0 char #\9)
(- (char->integer char)
(char->integer #\0))]
[(char<=? #\a char #\f)
(+ 10 (- (char->integer char)
(char->integer #\a)))]))
(define decoded
(decode-sexp
(apply
string-append
(map (λ (x) (symbol->string (syntax-e x)))
(syntax->list (syntax (arg ...)))))))
(datum->syntax stx decoded stx))]))
[(_ x ...)
(andmap (lambda (x) (or identifier? (integer? (syntax-e x))))
(syntax->list #'(x ...)))
(let* ([data (format "~a" (syntax->datum #'(x ...)))]
[data (substring data 1 (sub1 (string-length data)))]
[data (string->bytes/utf-8 data)]
[in (open-input-bytes (base64-decode data))]
[out (open-output-string)]
[out (begin (inflate in out) (get-output-string out))]
[exprs (read (open-input-string (string-append "(" out ")")))]
[exprs (datum->syntax stx exprs stx)])
#`(#%module-begin #,@exprs))]))

View File

@ -1,67 +1,43 @@
#lang scheme/base
(require mzlib/deflate
mzlib/match
mzlib/pretty)
(require (for-syntax mzlib/inflate
mzlib/string))
(require scheme/cmdline scheme/string scheme/match scheme/pretty
file/gzip file/gunzip net/base64)
(provide encode-sexp
encode-module)
(define (encode-exprs exprs)
(define in
(open-input-string
(string-join (map (lambda (x) (format "~s" x)) exprs) " ")))
(define out (open-output-bytes))
(deflate in out)
(base64-encode (get-output-bytes out)))
(define (encode-module in-filename out-filename)
(call-with-input-file in-filename
(λ (port)
(let ([mod (read port)])
(unless (eof-object? (read port))
(error 'encode-module "found an extra expression"))
(match mod
[`(module ,m mzscheme ,@(bodies ...))
(call-with-output-file out-filename
(λ (oport)
(let ([chopped (chop-up (encode-sexp `(begin ,@bodies)))])
(fprintf oport "(module ~a mzscheme\n" m)
(fprintf oport " (require framework/private/decode)\n")
(fprintf oport " (decode ~a" (car chopped))
(for-each (lambda (chopped)
(fprintf oport "\n ~a" chopped))
(cdr chopped))
(fprintf oport "))\n")))
'truncate 'text)]
[else (error 'encode-module "cannot parse module")])))))
(define (encode-module)
(define mod (parameterize ([read-accept-reader #t]) (read)))
(when (eof-object? mod) (error 'encode-module "missing module"))
(match mod
[(list 'module m 'scheme/base (list '#%module-begin exprs ...))
(write-bytes #"#lang s-exp framework/private/decode\n")
(write-bytes (regexp-replace* #rx"\r\n" (encode-exprs exprs) #"\n"))]
[else (error 'encode-module "cannot parse module, must use scheme/base")]))
(define (chop-up sym)
(let ([chopping-point 50])
(let loop ([str (symbol->string sym)])
(cond
[(<= (string-length str) chopping-point)
(list (string->symbol str))]
[else
(cons (string->symbol (substring str 0 chopping-point))
(loop (substring str chopping-point (string-length str))))]))))
(define (decode-module)
(define mod (parameterize ([read-accept-reader #t]) (read)))
(when (eof-object? mod) (error 'encode-module "missing module"))
(match mod
[(list 'module m 'framework/private/decode
(list '#%module-begin exprs ...))
(write-bytes #"#lang scheme/base\n")
(let* ([data (format "~a" exprs)]
[data (substring data 1 (sub1 (string-length data)))]
[data (string->bytes/utf-8 data)]
[in (open-input-bytes (base64-decode data))]
[out (open-output-string)]
[out (begin (inflate in out) (get-output-string out))]
[exprs (read (open-input-string (string-append "(" out ")")))])
(for ([expr (in-list exprs)])
(pretty-print expr)))]
[else (error 'decode-module "cannot parse module, must use scheme/base")]))
(define (encode-sexp sexp)
(define (str->sym string)
(string->symbol
(apply
string-append
(map
(λ (x)
(to-hex x))
(bytes->list string)))))
(define (to-hex n)
(let ([digit->hex
(λ (d)
(cond
[(<= d 9) d]
[else (integer->char (+ d -10 (char->integer #\a)))]))])
(cond
[(< n 16) (format "0~a" (digit->hex n))]
[else (format "~a~a"
(digit->hex (quotient n 16))
(digit->hex (modulo n 16)))])))
(let ([in (open-input-string (format "~s" sexp))]
[out (open-output-bytes)])
(deflate in out)
(str->sym (get-output-bytes out))))
(command-line #:once-any
["-e" "encode" (encode-module) (exit)]
["-d" "decode" (decode-module) (exit)])
(printf "Use `-h' for help\n")

View File

@ -4,7 +4,7 @@
(provide debug)
(define-for-syntax verbose? #f)
(define-for-syntax verbose? #t)
(define-syntax (debug stx)
(if verbose?
(syntax-case stx ()

View File

@ -126,6 +126,7 @@
(let ([v (syntax-local-value (stx-car first) (lambda () #f))])
(and (honu-transformer? v) v))]
[else #f]))))
;; (printf "~a bound transformer? ~a\n" stx (bound-transformer stx))
(or (bound-transformer stx)
(special-transformer stx)))

View File

@ -1,8 +1,13 @@
#lang scheme/base
(require "honu.ss"
(for-syntax "debug.ss")
(for-syntax scheme/base))
(for-syntax "debug.ss"
"contexts.ss"
scheme/base
syntax/parse
syntax/stx
scheme/pretty
scheme/trace))
(provide honu-macro)
@ -21,6 +26,9 @@
(loop out #'(rest1 rest ...))]
[(foo) out])))
(define-syntax (semicolon stx)
stx)
(define-for-syntax (extract-patterns pattern)
(let loop ([out '()]
[in pattern])
@ -36,6 +44,29 @@
#'(rest1 rest ...)))]
[(foo) (reverse (cons #'foo out))])))
#|
(define-for-syntax (convert stx)
(syntax-case stx (...)
[(_ x ...)
|#
(define-for-syntax (fix-template stx) stx)
#|
(define-for-syntax (fix-template stx)
[(any \;
(... ...) rest1 rest ...)
(loop (cons #'(semicolon any (... ..)))
#'(rest1 rest ...))]
[((any1 any ...) rest1 rest ...)
(loop (loop out #'(any1 any ...))
#'(rest1 rest ...))]
|#
;; x = 1 + y; ...
#;
(define-honu-syntax honu-macro
(lambda (stx ctx)
(debug "Original macro: ~a\n" (syntax->datum stx))
@ -47,7 +78,10 @@
(with-syntax ([(conventions ...)
(extract-conventions #'(pattern ...))]
[(raw-patterns ...)
(extract-patterns #'(pattern ...))])
(extract-patterns #'(pattern ...))]
[(fixed-template ...)
(fix-template #'(template ...))])
(debug "new template ~a\n" (syntax->datum #'(fixed-template ...)))
(values
(syntax/loc
stx
@ -80,7 +114,7 @@
[(name pattern ...)
#'(honu-unparsed-block
#f obj 'obj #f ctx
template ...)]))
fixed-template ...)]))
(let ([result (syntax-case stx
#;
@ -92,7 +126,7 @@
[(name raw-patterns ...)
#'(honu-unparsed-block
#f obj 'obj #f ctx
template ...)]
fixed-template ...)]
[else 'fail-boat])])
(debug "result was ~a\n" result))
(syntax-case stx (honu-literal ...)
@ -100,7 +134,7 @@
(values
#'(honu-unparsed-block
#f obj 'obj #f ctx
template ...)
fixed-template ...)
#'rrest)])))
#;
(define-honu-syntax name
@ -115,7 +149,289 @@
(values
#'(honu-unparsed-block
#f obj 'obj #f ctx
template ...)
fixed-template ...)
#'rrest)])))))
#'rest))])
))
(define-for-syntax (delimiter? x)
(or (free-identifier=? x #'\;)))
(define-syntax (my-ellipses stx) (raise-syntax-error 'my-ellipses "dont use this"))
;; (define-syntax (wrapped stx) (raise-syntax-error 'wrapped "dont use wrap"))
;; just a phase 0 identifier
(define wrapped #f)
(define unwrap #f)
(define-for-syntax (pull stx)
(define (reverse-syntax stx)
(with-syntax ([(x ...) (reverse (syntax->list stx))])
#'(x ...)))
(define-syntax-class stop-class
(pattern x:id #:when (or (free-identifier=? #'x #'(... ...))
(free-identifier=? #'x #'\;))))
(define (do-ellipses stx)
(let loop ([ellipses '()]
[body '()]
[stx stx])
(cond
[(null? stx) (values (with-syntax ([(ellipses ...) ellipses]
[(body ...) body])
#'(ellipses ... body ...))
stx)]
[(and (identifier? (car stx))
(free-identifier=? (car stx) #'(... ...)))
(loop (cons #'(... ...) ellipses) body (cdr stx))]
[(and (identifier? (car stx))
(free-identifier=? (car stx) #'\;))
;; (printf "Found a ; in ~a\n" (syntax->datum stx))
(with-syntax ([all (cdr stx)])
;; (printf "Found a ; -- ~a\n" (syntax->datum #'all))
(syntax-parse #'all
[((~and x (~not _:stop-class)) ... stop:stop-class y ...)
(with-syntax ([(ellipses ...) ellipses]
[(x* ...) (reverse-syntax #'(x ...))])
(values #'(ellipses ... (wrapped x* ... \;) unwrap)
#'(stop y ...)))]
[else (with-syntax ([(f ...) (reverse-syntax #'all)]
[(ellipses ...) ellipses])
(values #'(ellipses ... (wrapped f ... \;) unwrap)
#'()))]))])))
(let loop ([all '()]
[stx (reverse (syntax->list stx))])
(if (null? stx)
(with-syntax ([x all])
#'x)
(let ([head (car stx)]
[tail (cdr stx)])
(cond
[(and (identifier? head)
(free-identifier=? head #'(... ...)))
(let-values ([(wrapped rest) (do-ellipses (cons head tail))])
(loop (cons (reverse-syntax wrapped) all) (syntax->list rest)))]
[else (loop (cons head all) tail)])))))
;; rename this to wrap
#;
(define-for-syntax (pull stx)
(define (reverse-syntax stx)
(with-syntax ([(x ...) (reverse (syntax->list stx))])
#'(x ...)))
(define-syntax-class delimiter-class
(pattern x:id #:when (delimiter? #'x)))
(define-syntax-class ellipses-class
(pattern x:id #:when (free-identifier=? #'x #'(... ...))))
(define-syntax-class not-ellipses-class
(pattern x:id #:when (not (free-identifier=? #'x #'(... ...)))))
;; use this if you are defining your own ellipses identifier
#;
(define-syntax-class ellipses-class
#:literals (...)
(pattern my-ellipses))
(if (not (stx-pair? stx))
stx
(let ([stx (reverse (syntax->list stx))])
;; (debug-parse stx (ellipses1:ellipses-class ellipses:ellipses-class ... x ...))
;; (printf "stx is ~a\n" stx)
;; (printf "... = ~a\n" (free-identifier=? #'(... ...) (stx-car stx)))
(syntax-parse stx
[(before:not-ellipses-class ... ellipses1:ellipses-class ellipses:ellipses-class ... delimiter:delimiter-class x ...)
(with-syntax ([(x* ...) (reverse-syntax (pull #'(delimiter x ...)))])
(reverse-syntax
(with-syntax ([wrapped #'wrapped]
[original
(with-syntax ([(ellipses* ...) (map (lambda (_)
#'((... ...) (... ...)))
(syntax->list #'(ellipses1 ellipses ...)))]
[(x-new ...) (generate-temporaries #'(delimiter x ...))])
(reverse-syntax #'(before ... ellipses* ... x-new ...)))]
#;
[original (syntax->datum (reverse-syntax #'(ellipses1 ellipses ... x ...)))])
#'(ellipses1 ellipses ... (wrapped x* ...) unwrap))))]
[(ellipses1:ellipses-class ellipses:ellipses-class ... x ...)
(with-syntax ([(x* ...) (reverse-syntax (pull #'(x ...)))])
(reverse-syntax
(with-syntax ([wrapped #'wrapped]
[original
(with-syntax ([(ellipses* ...) (map (lambda (_)
#'((... ...) (... ...)))
(syntax->list #'(ellipses1 ellipses ...)))]
[(x-new ...) (generate-temporaries #'(x ...))])
(reverse-syntax #'(ellipses* ... x-new ...)))]
#;
[original (syntax->datum (reverse-syntax #'(ellipses1 ellipses ... x ...)))])
#'(ellipses1 ellipses ... (wrapped x* ...) unwrap))))]
[(x ...) (with-syntax ([(x* ...) (map pull (syntax->list #'(x ...)))])
(reverse-syntax #'(x* ...)))]))))
;; (begin-for-syntax (trace pull))
(define-for-syntax (unpull stx)
(define-syntax-class ellipses-class
(pattern x:id #:when (free-identifier=? #'x #'(... ...))))
(define-syntax-class delimiter-class
(pattern x:id #:when (delimiter? #'x)))
;; (printf "unpull ~a\n" (syntax->datum stx))
(syntax-parse stx
#:literals (wrapped unwrap)
[((~and z (~not (unwrap _ ...))) ... (unwrap (wrapped x ... delimiter:delimiter-class) ...) rest ...)
(with-syntax ([(x1 ...) (apply append (map syntax->list (syntax->list #'((x ... delimiter) ...))))]
[(rest* ...) (unpull #'(rest ...))])
#'(z ... x1 ... rest* ...))]
[(unwrap (wrapped x ... delimiter:delimiter-class) ...)
(with-syntax ([(x1 ...) (apply append (map syntax->list (syntax->list #'((x ... delimiter) ...))))])
#'(x1 ...))]
[(unwrap (wrapped x ... y) ...)
(with-syntax ([(x1 ...) (car (syntax->list #'((x ...) ...)))])
(with-syntax ([(x1* ...) (map unpull (syntax->list #'(x1 ...)))]
[(y* ...) (map unpull (syntax->list #'(y ...)))])
#'(x1* ... y* ...)))]
[(unwrap . x) (raise-syntax-error 'unpull "unhandled unwrap ~a" stx)]
[(x ...) (with-syntax ([(x* ...) (map unpull (syntax->list #'(x ...)))])
#'(x* ...))]
[else stx]))
;; rename this to unwrap
#;
(define-syntax (unpull stx)
(define-syntax-class ellipses-class
(pattern x:id #:when (free-identifier=? #'x #'(... ...))))
(define (do-it stx)
(syntax-parse stx
#:literals (wrapped)
[((wrapped x ... y) ...)
(with-syntax ([(x1 ...) (car (syntax->list #'((x ...) ...)))])
#'(x1 ... y ...))]
[((wrapped x ...) ellipses1:ellipses-class ellipses:ellipses-class ...)
(with-syntax ([(x* ...) (map do-it (syntax->list #'(x ...)))])
#'(x* ... ellipses1 ellipses ...))]
[(x ...) (with-syntax ([(x* ...) (map do-it (syntax->list #'(x ...)))])
#'(x* ...))]
[else stx]))
(syntax-case stx ()
[(_ x ...) (do-it #'(x ...))]))
;; (provide unpull)
#;
(define-honu-syntax unpull
(lambda (stx ctx)
(define-syntax-class ellipses-class
(pattern x:id #:when (free-identifier=? #'x #'(... ...))))
(define (do-it stx)
(syntax-parse stx
#:literals (wrapped)
[((wrapped x ... y) ...)
(with-syntax ([(x1 ...) (car (syntax->list #'((x ...) ...)))])
#'(x1 ... y ...))]
[((wrapped x ...) ellipses1:ellipses-class ellipses:ellipses-class ...)
(with-syntax ([(x* ...) (map do-it (syntax->list #'(x ...)))])
#'(x* ... ellipses1 ellipses ...))]
[(x ...) (with-syntax ([(x* ...) (map do-it (syntax->list #'(x ...)))])
(printf "x* is ~a\n" #'(x* ...))
#'(x* ...))]
[else stx]))
(syntax-case stx ()
[(_ x ...) (values (do-it #'(x ...))
#'())])))
#;
(define-syntax (test stx)
(syntax-case stx ()
[(_ x ...)
(begin
(pretty-print (syntax->datum (pull #'(x ...))))
(pretty-print (syntax->datum (unpull (pull #'(x ...)))))
#'1)]))
(define-syntax (my-syntax stx)
(syntax-case stx ()
[(_ name pattern template)
(with-syntax ([wrap-it (pull #'template)])
#'(define-syntax (name stx)
(syntax-case stx ()
[pattern #'wrap-it]
[else (raise-syntax-error 'name (format "~a does not match pattern ~a"
(syntax->datum stx)
'pattern))]
)))]))
(define-syntax (test2 stx)
(syntax-case stx ()
[(_ x ...)
(begin
(with-syntax ([pulled (pull #'(x ...))])
#'(unpull pulled)))]))
(define-honu-syntax honu-macro
(lambda (stx ctx)
(syntax-case stx (#%parens #%braces)
[(_ (#%parens honu-literal ...)
(#%braces (#%braces name pattern ...))
(#%braces (#%braces template ...))
. rest)
(with-syntax ([pulled (pull #'(template ...))]
[(pattern* ...) (map (lambda (stx)
(if (and (identifier? stx)
(not (ormap (lambda (f)
(free-identifier=? stx f))
(syntax->list #'(honu-literal ...))))
(not (free-identifier=? stx #'(... ...))))
(with-syntax ([x stx])
#'(~and x (~not (~or honu-literal ...))))
stx))
(syntax->list #'(pattern ...)))]
)
(values
#'(define-honu-syntax name
(lambda (stx ctx)
;; (define-literal-set literals (honu-literal ...))
(syntax-parse stx
;; #:literal-sets (literals)
#:literals (honu-literal ...)
[(name pattern* ... . rrest)
(with-syntax ([(out (... ...)) (unpull #'pulled)])
(define (X) (raise-syntax-error (syntax->datum #'name) "implement for this context"))
(values
;; this is sort of ugly, is there a better way?
(cond
[(type-context? ctx) (X)]
[(type-or-expression-context? ctx) (X)]
[(expression-context? ctx) #'(honu-unparsed-expr out (... ...))]
[(expression-block-context? ctx)
#'(honu-unparsed-begin out (... ...))]
[(block-context? ctx)
#'(honu-unparsed-begin out (... ...))]
[(variable-definition-context? ctx) (X)]
[(constant-definition-context? ctx) (X)]
[(function-definition-context? ctx) (X)]
[(prototype-context? ctx) (X)]
[else #'(honu-unparsed-expr out (... ...))])
#;
#'(honu-unparsed-begin out (... ...))
#'rrest)
#;
#'(honu-unparsed-block
#f obj 'obj #f ctx
out (... ...))
#;
(values
#;
#'(honu-unparsed-expr out (... ...))
#'(honu-unparsed-block
#f obj 'obj #f ctx
out (... ...) rrest)
#;
#'rrest))])))
#'rest))])))
;; (my-syntax guz (_ display (#%parens x ...)) (+ x ...))
;; (guz display (#%parens 1 2 3 4))
;; (local-expand stx 'expression (list #'wrapped))
#|
(begin-for-syntax
(trace pull))
(test display (#%parens x))
(test display (#%parens x ... ...) ...)
|#

View File

@ -407,7 +407,7 @@ plt/collects/tests/mzscheme/htdp-image.ss
(cond
[(string=? str "")
(let-values ([(tw th) (get-text-size size "dummyX")])
(rectangle 0 th 'solid 'black))]
(put-pinhole (rectangle 0 th 'solid 'black) 0 0))]
[else
(let ([color (make-color% color-in)])
(let-values ([(tw th) (get-text-size size str)])

View File

@ -1 +1,22 @@
(module show-queen mzscheme (require framework/private/decode) (decode ad56db8ee3360cfd15368b05eca6eecc60fbb05834cd1f14e81714b2cd444a65c923cbb9ec43bfbda464d97226b3e8167db2c5cb21451d512c6a3c2a0385c3d751398442ab1a369dc3f6e761d8c4bf4d39891b2d8681e525497a67cfaa4518a4bd54af23a221618b0765107a876765c7a13a38d1217c382caae6231401071a61ce62a0e541a16ea13857b515ae850fcf05e30fea2bc273397b3ef563ad55038532ca4330652bf43f40f2a42c075ffd76c6c65b0745277a5849a25399dc428422ea2a8de6e86582621b6baa5e28e3f3149c3a0b4f4e47f4a0e054ceee0e0fabff94922ac9aae4a4253aca9b1cab462b34be0ae179dd36e55c844ec56a7527fe2e91ed199de372735a78267fc0b3277d630db915bcdf01e997a4d0d1c998e3becc44e440f159c88749d9170589af99056772652d2d6e77f21bcb0f76346d650deea7d40eb457148dac06dab7b2c4222dbaba15b45b38c1156ee0a51aaa4bfc48f2b848242bc119ffba238b98c296fea225a392e20631876d8290cba1e559f0fe47a391c8144189c442efe9643a55ceab1374a7d99deaabe6ff5338c1e59c439409308bb38e61ac8ff0e167851c4e2e4187c51df652558d229d512c0a1d202174a7ef817bc48da84f67dc3681ab4cb1ff766203f3d56aeb0620ac4dad45f317b505ad8ed21f9db86d12c948db3a7121f2375e98a3c66f1060b93d8a6e8d970ee952196cabfab68f5598d4ef449f7ad23b5aeb283e6ecafbcc506bd50f18f9563ca5dc3eb321332d896414fd980c3e3dfdb22c6558962b2ec78c8b5de2dd2ea7dca30c8f8ebae59bcafdaff9ad0832b7ad37e77f884ca9ce428f480c2f8a0bf039ddb5a972e91a976af0d843f13a5acf7ab840b48042deab24ac9cb5b5a425aa3d93e04a1df740809d6d476d33946b6cfae9ce7155832a2530ed3a50e72b3abb870855424a6d9bfe5ecafbd8a710fbb68e2de7d8b7fbd8a707b1651efb36c596736cb98a7d80f76e56cc684bda97f211e23314d5b460b0bb6e586608ea0ee19a235c57084ba34d1419c61e5d65f09211e69eb87df8853a7c32dab255cfb72008bc445e55fce402c150f7745513ee76b09a505e22416870b05aa5d778c1abdd38c80c31ac1f6246cb98d43d66b6956fb497ecf232c42ebd0ebbf434ecb882d1b69ada73946e27e93649f3900f869e30eaac44c53237cdc3cca4fa934a348d65ab97878bb09f8d49c403cedcc1afe5caecba98d4d6d27363584659cef30d3d1a59e1b2296e83d79efa03b620c2fc04f6307f27ac01683bcaf4a3ff098ed67f81bf71b320c7d66846ad9774df8f46a71ca1a01b29488d14360e4f17451399088f2547e7425293dc64cd48f17ee3e4b60c7759d1de546807b94f56907f550f4e7572a55af0ca8e3457c5ea780b9df08d04eeb049cfd6d20f69a98c99cc87b785cbbaac41a26b1874c3981118b5bc3a9936ce448170e47489bf1f79cf356ad8fc0e7ff01e067e6c68e394f7a767ee8012f9010f8b798099481a60784aef85e3269e62a77b3a99ada6f0b7599161cc8a0bc9931afb9f6db89cff00))
#lang s-exp framework/private/decode
rVbbjqQ2EP2VSq9WgnTIzGjzsFql038QKV8QGSja7oDNGNOXfci3p8rGYJieVTbKE7gup8rl
43JlFl9HZRGyVpWw6yzWPw/DLvzt8klctWIYWJ6TpLfmomqEQZpr8ToiahLW2CiN0Fu8KDMO
RWNFh/ChWVTVR8g8DlRCX8RAy0ZhW0N2KUojbA0fMoYf1FeE53x2fOrHslUVZEorB96SrdD9
ANGRkhxc8dsFK2csZJ3oYSUJTnl08xGyoCta1CcnIxTbGF30QmmXpmDVRThyOqEDBed8drfY
rP5jSionq5yTlmgpb3IsqlahdoUPz+u6yucadCoUqzvzd4lsLmgtV5vTwgv5A14c6SujyS3j
/Q5IvySFjg5Gn455IiIHis9CPkvKPstIfEssOJMba2lx38jvLG/MqOvCaDxOqTW0VxSVLAba
tzKagEVX1oJ2C2e4wR2cVENxDR9JHleJZCU4418PZBFS2NNfsGRUUtwh5LCPEHI5tDQL3v+o
WyQuBVDisGiPdDKdyufVGbrz7E71VfP/2Z/gcs4+ygSYxFnH0MYFeP+zQvYnF6H9YoO9VLVF
Ec8oFIUOkBC68/fAPeJG0MczrivPVabYfzuxgflqWmMHIKxd2YrqL+oKrTpJd7LivoskI21t
xZXIXzmhTy1+gwDL7VF0a5y0SJdKY12U92OowqR+J/rUkt7RGkvxcZdvM8O2Vf2AgW/ZU8zt
Mxsy06JIBtGP0eDT0y/LUvplvuJyyDg7RN4dUso9yvBkqVm+qdz/mt+KIHPbenP+TWBKcRHt
iMTwLLsCn9OmTeVL17gWg8MestfRONbDFYIFZHKrkrBybo0hLVHtmQQ36rgNAXamHluToNxC
0493jqvqVTGBadeeOl/RmiMEqBxiavv495JvY5997Ps6tpxj37exzw9iyzT2fYot59hyFbuB
925WyGhP2pf8EeIzZMW0YLBNN8wTBLVBuKUItxXC0mgjRYaxR1tovCaE2RK3979Q+k9CW7bq
+RZ4gZPIq4KfXCAY6p62qPzd9lYTyksgCM0NplXxNV7wSjsOMkH064eYwTIktcVMtvKN9pJc
XoY4xNfhEJ+GA1cw2BZTew7S/STdR2ka8sHM4yedlShbxqZ5mJlUf1KJSjwpvXl5uAjH2ZhE
PODMHfyWr8xui0lpDD03mmWU5Tzf0KORFC4Z4nZ466k/YA3Cz09gmvk7YQ1A21G6H91PcDLu
C/yNuwU5tEY9tu2S7vvR6JQDFHQjBSmRwobh6apoIhP+seToXEhqkrukGSneb5jcluEuKdqb
Ch0g9UkK8q/qwalOrlQLXpmR5qpQHWegE66SwB026tlauiEuldaT+fC2cEmX1Uh09YOuHzM8
o5ZXJ9GGmcgTjpyu4fcj77nEFna/wx+8h4EfG9o45f3pmTugRH7A/WIeYCaSehge0nthuYnH
2PGeTmarKfxtVmQYsuJC8qTG/hfDl/Mf

View File

@ -8,6 +8,9 @@
(define tool-names (list "How to Design Programs"))
(define tool-urls (list "http://www.htdp.org/"))
(define compile-omit-paths
'("test-error.ss"))
(define textbook-pls
(list (list '("htdp-icon.gif" "icons")
"How to Design Programs"

View File

@ -38,4 +38,3 @@ string-ref : String Nat -> Char
NOTE:
substring consumes 2 or 3 arguments

View File

@ -192,8 +192,25 @@ namespace.
(apply append x)))))
(define-teach beginner error
(lambda stuff0
(define-values (f stuff1)
(if (and (cons? stuff0) (symbol? (first stuff0)))
(values (first stuff0) (rest stuff0))
(values false stuff0)))
(define str
(let loop ([stuff stuff1][frmt ""][pieces '()])
(cond
[(empty? stuff) (apply format frmt (reverse pieces))]
[else
(let ([f (first stuff)]
[r (rest stuff)])
(if (string? f)
(loop r (string-append frmt f) pieces)
(loop r (string-append frmt "~e") (cons f pieces))))])))
(if f (error f str) (error str)))
#;
(lambda (str)
(unless (string? str)
(unless (string? str)
(raise
(make-exn:fail:contract
(format "error: expected a string, got ~e and ~e" str)

View File

@ -0,0 +1,16 @@
;; The first three lines of this file were inserted by DrScheme. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-beginner-reader.ss" "lang")((modname bar) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
(check-error (error) "")
(check-error (error 1) "1")
(check-error (error 'a) "a: ")
(check-error (error 'a "bad input") "a: bad input")
(check-error (error 'a "bad input: " 1) "a: bad input: 1")
(check-error (error 'a "bad input: " 1 " and " "hello") "a: bad input: 1 and hello")
(check-error (error 'a "bad input: " 1 " and " false) "a: bad input: 1 and false")
(check-error (error 'a "uhoh " (list 1 2 3)) "a: uhoh (cons 1 (cons 2 (cons 3 empty)))")
(define-struct err (str))
(check-error (error 'a "bad input: " 1 " and " (make-err "hello"))
"a: bad input: 1 and (make-err \"hello\")")

View File

@ -1,7 +1,8 @@
#lang scribble/doc
@(require (for-label (except-in lazy delay force)
(only-in lazy/force ! !! !list !!list)
scheme/contract))
scheme/contract
(only-in scheme/promise promise?)))
@(define-syntax-rule (deflazy mod def id)
(begin

View File

@ -285,7 +285,7 @@
(send dc set-text-foreground color)
(send dc draw-text "?"
(+ endx dx fw)
(- endy dy fh)))))))])
(- (+ endy dy) fh)))))))])
(add-mouse-drawing from1 from2 draw tack-box)
(add-mouse-drawing to1 to2 draw tack-box))))

View File

@ -626,21 +626,23 @@ the mask bitmap and the original bitmap are all together in a single bytes!
[orig-h (send orig-bm get-height)]
[x-scale (bitmap-x-scale bitmap)]
[y-scale (bitmap-y-scale bitmap)]
[scale-w (* x-scale (send orig-bm get-width))]
[scale-h (* y-scale (send orig-bm get-height))]
[scale-w (ceiling (inexact->exact (* x-scale (send orig-bm get-width))))]
[scale-h (ceiling (inexact->exact (* y-scale (send orig-bm get-height))))]
[new-bm (make-object bitmap% scale-w scale-h)]
[new-mask (make-object bitmap% scale-w scale-h)])
(send new-bm set-loaded-mask new-mask)
[new-mask (and orig-mask (make-object bitmap% scale-w scale-h))])
(when new-mask
(send new-bm set-loaded-mask new-mask))
(send bdc set-bitmap new-bm)
(send bdc set-scale x-scale y-scale)
(send bdc clear)
(send bdc draw-bitmap orig-bm 0 0)
(send bdc set-bitmap new-mask)
(send bdc set-scale x-scale y-scale)
(send bdc clear)
(send bdc draw-bitmap orig-mask 0 0)
(when new-mask
(send bdc set-bitmap new-mask)
(send bdc set-scale x-scale y-scale)
(send bdc clear)
(send bdc draw-bitmap orig-mask 0 0))
(send bdc set-bitmap #f)
@ -734,6 +736,6 @@ the mask bitmap and the original bitmap are all together in a single bytes!
render-image)
;; method names
(provide get-shape get-bb get-normalized?)
(provide get-shape get-bb get-normalized? get-normalized-shape)
(provide np-atomic-shape? atomic-shape? simple-shape?)

View File

@ -59,8 +59,8 @@ instead of this scaling code, we use the dc<%>'s scaling code.
[h (send bm get-height)]
[bytes (make-bytes (* w h NUM-CHANNELS) 0)])
(send bm get-argb-pixels 0 0 w h bytes #f)
(when (send bm get-loaded-mask)
(send (send bm get-loaded-mask) get-argb-pixels 0 0 w h bytes #t))
(when mask
(send mask get-argb-pixels 0 0 w h bytes #t))
(values bytes w h)))
(define (bytes->bitmap bytes w h)

View File

@ -1,57 +1,63 @@
#lang scheme/base
(require scheme/function
scheme/path
scheme/file)
(provide compile-file)
(module compile mzscheme
(require "file.ss"
"port.ss")
(provide compile-file)
;; (require compiler/src2src)
(define compile-file
(case-lambda
[(src)
(let-values ([(base name dir?) (split-path src)])
(let ([cdir (build-path
(if (symbol? base)
'same
base)
"compiled")])
(unless (directory-exists? cdir)
(make-directory cdir))
(compile-file src (build-path cdir (path-add-suffix name #".zo")))))]
[(src dest) (compile-file src dest values)]
[(src dest filter)
(let ([in (open-input-file src)])
(dynamic-wind
void
(lambda ()
(port-count-lines! in)
(with-handlers ([void
(lambda (exn)
(with-handlers ([void void])
(delete-file dest))
(raise exn))])
(let ([out (open-output-file dest 'truncate/replace)]
[ok? #f])
(let ([dir (let-values ([(base name dir?) (split-path src)])
(if (eq? base 'relative)
(current-directory)
(path->complete-path base (current-directory))))])
(parameterize ([current-load-relative-directory dir]
[current-write-relative-directory dir])
(dynamic-wind
void
(lambda ()
(let loop ()
(let ([r (read-syntax src in)])
(unless (eof-object? r)
(write (compile-syntax (filter (namespace-syntax-introduce r))) out)
(loop))))
(set! ok? #t))
(lambda ()
(close-output-port out)
(unless ok?
(with-handlers ([void void])
(delete-file dest))))))))))
(lambda () (close-input-port in))))
dest])))
(define compile-file
(case-lambda
[(src)
(define cdir (build-path (path-only src) "compiled"))
(make-directory* cdir)
(compile-file src (build-path cdir (path-add-suffix (file-name-from-path src) #".zo")))]
[(src dest)
(compile-file src dest values)]
[(src dest filter)
(define in (open-input-file src))
(dynamic-wind
void
(lambda ()
(define ok? #f)
; This must be based on the path to dest. Renaming typically cannot be done
; atomically across file systems, so the temporary directory is not an option
; because it is often a ram disk. src (or dir below) couldn't be used because
; it may be on a different filesystem. Since dest must be a file path, this
; guarantees that the temp file is in the same directory. It would take a weird
; filesystem configuration to break that.
(define temp-filename (make-temporary-file "tmp~a" #f (path-only dest)))
(port-count-lines! in)
(dynamic-wind
void
(lambda ()
; XXX: This seems like it should be a library function named 'relative-path-only'
(define dir
(let-values ([(base name dir?) (split-path src)])
(if (eq? base 'relative)
(current-directory)
(path->complete-path base (current-directory)))))
(define out (open-output-file temp-filename #:exists 'truncate/replace))
(parameterize ([current-load-relative-directory dir]
[current-write-relative-directory dir])
; Rather than installing a continuation barrier, we detect reinvocation.
; The only thing that can cause reinvocation is if the filter captures the
; continuation and communicates it externally.
(define count 0)
(dynamic-wind
(lambda ()
(if (zero? count)
(set! count 1)
(error 'compile-file "filter function should not be re-entrant")))
(lambda ()
(for ([r (in-port (curry read-syntax src) in)])
(write (compile-syntax (filter (namespace-syntax-introduce r))) out))
(set! ok? #t))
(lambda ()
(close-output-port out)))))
(lambda ()
(if ok?
(rename-file-or-directory temp-filename dest)
(with-handlers ([exn:fail:filesystem? void])
(delete-file temp-filename))))))
(lambda () (close-input-port in)))
dest]))

View File

@ -6,13 +6,14 @@
[planet-get-info get-info]))
(define-values (planet-read planet-read-syntax planet-get-info)
(make-meta-reader 'planet
"planet path"
(lambda (str)
(let ([str (bytes->string/latin-1 str)])
(if (module-path? `(planet ,(string->symbol str)))
`(planet ,(string->symbol (string-append str "/lang/reader")))
#f)))
values
values
values)))
(make-meta-reader
'planet
"planet path"
(lambda (str)
(let ([str (bytes->string/latin-1 str)])
(if (module-path? `(planet ,(string->symbol str)))
`(planet ,(string->symbol (string-append str "/lang/reader")))
#f)))
values
values
values)))

View File

@ -6,11 +6,11 @@
[-get-info get-info]))
(define-values (-read -read-syntax -get-info)
(make-meta-reader 'reader
"language path"
#:read-spec (lambda (in) (read in))
(lambda (s)
(and (module-path? s) s))
values
values
values)))
(make-meta-reader
'reader
"language path"
#:read-spec (lambda (in) (read in))
(lambda (s) (and (module-path? s) s))
values
values
values)))

View File

@ -712,12 +712,6 @@ before the pattern compiler is invoked.
[(has-underscore? pattern)
(let*-values ([(binder before-underscore)
(let ([before (split-underscore pattern)])
(unless (or (hash-maps? clang-ht before)
(memq before underscore-allowed))
(error 'compile-pattern "before underscore must be either a non-terminal ~a or a built-in pattern, found ~a in ~s"
before
(format "~s" (list* 'one 'of: (hash-map clang-ht (λ (x y) x))))
pattern))
(values pattern before))]
[(match-raw-name has-hole?)
(compile-id-pattern before-underscore)])

View File

@ -1,4 +1,4 @@
(module rewrite-side-conditions scheme/base
(module rewrite-side-conditions scheme
(require (lib "list.ss")
"underscore-allowed.ss")
(require (for-template
@ -74,6 +74,20 @@
[(cross a) #`(cross #,(loop #'a))]
[(cross a ...) (expected-exact 'cross 1 term)]
[cross (expected-arguments 'cross term)]
[_
(identifier? term)
(match (regexp-match #rx"^([^_]*)_.*" (symbol->string (syntax-e term)))
[(list _ (app string->symbol s))
(if (or (memq s (cons '... underscore-allowed))
(memq s all-nts))
term
(raise-syntax-error
what
(format "before underscore must be either a non-terminal or a built-in pattern, found ~a in ~s"
s (syntax-e term))
orig-stx
term))]
[_ term])]
[(terms ...)
(map loop (syntax->list (syntax (terms ...))))]
[else

View File

@ -1,9 +1,7 @@
(module term-test scheme
(require "term.ss"
"matcher.ss"
"test-util.ss"
errortrace/errortrace-lib
errortrace/errortrace-key)
"test-util.ss")
(reset-count)
(test (term 1) 1)
@ -105,58 +103,75 @@
(define-namespace-anchor here)
(define ns (namespace-anchor->namespace here))
(define (runtime-error-source sexp src)
(let/ec return
(cadar
(continuation-mark-set->list
(exn-continuation-marks
(with-handlers ((exn:fail? values))
(parameterize ([current-namespace ns])
(parameterize ([current-compile (make-errortrace-compile-handler)])
(eval (read-syntax src (open-input-string (format "~s" sexp))))))
(return 'no-source)))
errortrace-key))))
(let ([src 'term-template])
(test
(runtime-error-source
'(term-let ([(x ...) '(a b c)]
[((y ...) ...) '((1 2) (4 5 6) (7 8 9))])
(term (((x y) ...) ...)))
src)
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let ([(x ...) '(a b c)]
[((y ...) ...) '((1 2) (4 5 6) (7 8 9))])
(term (((x y) ...) ...)))
src))
src))
(let ([src 'term-template-metafunc])
(test
(runtime-error-source
'(term-let-fn ((f car))
(term-let ([(x ...) '(a b c)]
[((y ...) ...) '((1 2) (4 5 6) (7 8 9))])
(term ((((f x) y) ...) ...))))
src)
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let-fn ((f car))
(term-let ([(x ...) '(a b c)]
[((y ...) ...) '((1 2) (4 5 6) (7 8 9))])
(term ((((f x) y) ...) ...))))
src))
src))
(let ([src 'ellipsis-args])
(test
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let-fn ((f car))
(term-let ([(x ...) '(a b)]
[(y ...) '(c d e)])
(term (f ((x y) ...)))))
src))
src))
(let ([src 'ellipsis-args/map])
(test
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let-fn ((f car))
(term-let ([(x ...) '(a b)]
[(y ...) '(c d e)])
(term ((f (x y)) ...))))
src))
src))
(let ([src 'ellipsis-args/in-hole])
(test
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let ([(x ...) '(a b)]
[(y ...) '(c d e)])
(term ((in-hole hole (x y)) ...)))
src))
src))
(let ([src 'term-let-rhs])
(test
(runtime-error-source
'(term-let ([(x ...) 'a])
3)
src)
(parameterize ([current-namespace ns])
(runtime-error-source
'(term-let ([(x ...) 'a])
3)
src))
src))
(define (syntax-error-sources sexp src)
(let ([p (read-syntax src (open-input-string (format "~s" sexp)))])
(with-handlers ((exn:srclocs? (λ (x) (map srcloc-source ((exn:srclocs-accessor x) x)))))
(parameterize ([current-namespace ns])
(expand p))
null)))
(let ([src 'term-template])
(test
(syntax-error-sources
'(term-let ([(x ...) '(a b c)])
(term x))
src)
(parameterize ([current-namespace ns])
(syntax-error-sources
'(term-let ([(x ...) '(a b c)])
(term x))
src))
(list src)))
(print-tests-passed 'term-test.ss))

View File

@ -32,11 +32,11 @@
(let ([result-id (car (generate-temporaries '(f-results)))])
(with-syntax ([fn fn])
(let loop ([func (syntax (λ (x) (fn (syntax->datum x))))]
[args rewritten]
[args-stx rewritten]
[res result-id]
[args-depth (min depth max-depth)])
(with-syntax ([func func]
[args args]
[args args-stx]
[res res])
(if (zero? args-depth)
(begin
@ -45,7 +45,7 @@
outer-bindings))
(values result-id (min depth max-depth)))
(loop (syntax (λ (l) (map func (syntax->list l))))
(syntax (args (... ...)))
(syntax/loc args-stx (args (... ...)))
(syntax (res (... ...)))
(sub1 args-depth)))))))))
@ -55,7 +55,7 @@
(and (identifier? (syntax metafunc-name))
(term-fn? (syntax-local-value (syntax metafunc-name) (λ () #f))))
(rewrite-application (term-fn-get-id (syntax-local-value/catch (syntax metafunc-name) (λ (x) #t)))
(syntax (arg ...))
(syntax/loc stx (arg ...))
depth)]
[f
(and (identifier? (syntax f))
@ -76,7 +76,7 @@
[(unquote-splicing . x)
(raise-syntax-error 'term "malformed unquote splicing" orig-stx stx)]
[(in-hole id body)
(rewrite-application (syntax (λ (x) (apply plug x))) (syntax (id body)) depth)]
(rewrite-application (syntax (λ (x) (apply plug x))) (syntax/loc stx (id body)) depth)]
[(in-hole . x)
(raise-syntax-error 'term "malformed in-hole" orig-stx stx)]
[hole (values (syntax (unsyntax the-hole)) 0)]

View File

@ -1,10 +1,13 @@
#lang scheme
(require "matcher.ss")
(require "matcher.ss"
errortrace/errortrace-lib
errortrace/errortrace-key)
(provide test test-syn-err tests reset-count
syn-err-test-namespace
print-tests-passed
equal/bindings?)
equal/bindings?
runtime-error-source syntax-error-sources)
(define syn-err-test-namespace (make-base-namespace))
(parameterize ([current-namespace syn-err-test-namespace])
@ -108,3 +111,20 @@
;; rib-lt : rib rib -> boolean
(define (rib-lt r1 r2) (string<=? (format "~s" (bind-name r1))
(format "~s" (bind-name r2))))
(define (runtime-error-source sexp src)
(let/ec return
(cadar
(continuation-mark-set->list
(exn-continuation-marks
(with-handlers ((exn:fail? values))
(parameterize ([current-compile (make-errortrace-compile-handler)])
(eval (read-syntax src (open-input-string (format "~s" sexp)))))
(return 'no-source)))
errortrace-key))))
(define (syntax-error-sources sexp src)
(let ([p (read-syntax src (open-input-string (format "~s" sexp)))])
(with-handlers ((exn:srclocs? (λ (x) (map srcloc-source ((exn:srclocs-accessor x) x)))))
(expand p)
null)))

View File

@ -261,7 +261,16 @@
(term (f 1)))
(test rhs-eval-count 2))
(define-namespace-anchor here)
(define ns (namespace-anchor->namespace here))
(let ([src 'bad-underscore])
(test
(parameterize ([current-namespace ns])
(syntax-error-sources
'(define-language L (n m_1))
src))
(list src)))
;
;

View File

@ -128,7 +128,7 @@ in the grammar are terminals.
@itemize[
@item{The @defpattech[any] @pattern matches any sepxression.
@item{The @defpattech[any] @pattern matches any sexpression.
This @pattern may also be suffixed with an underscore and another
identifier, in which case they bind the full name (as if it
were an implicit @pattech[name] @pattern) and match the portion
@ -192,9 +192,9 @@ symbol except those that are used as literals elsewhere in
the language.
}
@item{The @defpattech[hole] @pattern matches anything when inside a matching
@item{The @defpattech[hole] @pattern matches anything when inside
the first argument to an @pattech[in-hole] @|pattern|. Otherwise,
it matches only the hole.
it matches only a hole.
}
@item{The @defpattech[symbol] @pattern stands for a literal symbol that must

View File

@ -1 +1 @@
#lang scheme/base (provide stamp) (define stamp "23nov2009")
#lang scheme/base (provide stamp) (define stamp "9dec2009")

View File

@ -66,9 +66,14 @@
(define-values (flat-prop flat-pred? flat-get)
(make-struct-type-property 'contract-flat))
(define-values (first-order-prop first-order-pred? first-order-get)
(define-values (first-order-prop first-order-pred? raw-first-order-get)
(make-struct-type-property 'contract-first-order))
(define (first-order-get stct)
(cond
[(flat-pred? stct) (flat-get stct)]
[else (raw-first-order-get stct)]))
(define (contract-first-order-passes? c v)
(let ([ctc (coerce-contract 'contract-first-order-passes? c)])
(cond
@ -404,7 +409,8 @@
#:property name-prop (λ (ctc) (apply build-compound-type-name 'and/c (and/c-ctcs ctc)))
#:property first-order-prop
(λ (ctc)
(let ([tests (map (λ (x) ((first-order-get x) x)) (and/c-ctcs ctc))])
(let ([tests (map (λ (x) ((first-order-get x) x))
(and/c-ctcs ctc))])
(λ (x)
(andmap (λ (f) (f x)) tests))))
#:property stronger-prop

View File

@ -56,8 +56,14 @@
;; struct for color-keeping across opters
(define-struct opt/info (contract val pos neg src-info orig-str positive-position?
free-vars recf base-pred this that))
(define-struct opt/info
(contract val pos neg src-info orig-str position-var position-swap?
free-vars recf base-pred this that))
(define (opt/info-positive-position? oi)
(if (opt/info-position-swap? oi)
#`(not #,(opt/info-position-var oi))
(opt/info-position-var oi)))
;; opt/info-swap-blame : opt/info -> opt/info
;; swaps pos and neg
@ -66,7 +72,8 @@
(val (opt/info-val info))
(pos (opt/info-pos info))
(neg (opt/info-neg info))
(positive-position? (opt/info-positive-position? info))
(position-var (opt/info-position-var info))
(position-swap? (opt/info-position-swap? info))
(src-info (opt/info-src-info info))
(orig-str (opt/info-orig-str info))
(free-vars (opt/info-free-vars info))
@ -74,7 +81,8 @@
(base-pred (opt/info-base-pred info))
(this (opt/info-this info))
(that (opt/info-that info)))
(make-opt/info ctc val neg pos src-info orig-str (not positive-position?)
(make-opt/info ctc val neg pos src-info orig-str
position-var (not position-swap?)
free-vars recf base-pred this that)))
;; opt/info-change-val : identifier opt/info -> opt/info
@ -83,7 +91,8 @@
(let ((ctc (opt/info-contract info))
(pos (opt/info-pos info))
(neg (opt/info-neg info))
(positive-position? (opt/info-positive-position? info))
(position-var (opt/info-position-var info))
(position-swap? (opt/info-position-swap? info))
(src-info (opt/info-src-info info))
(orig-str (opt/info-orig-str info))
(free-vars (opt/info-free-vars info))
@ -91,7 +100,9 @@
(base-pred (opt/info-base-pred info))
(this (opt/info-this info))
(that (opt/info-that info)))
(make-opt/info ctc val pos neg src-info orig-str positive-position? free-vars recf base-pred this that)))
(make-opt/info ctc val pos neg src-info orig-str
position-var position-swap?
free-vars recf base-pred this that)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -127,6 +127,7 @@
#'src-info
#'orig-str
#'positive-position?
#f
(syntax->list #'(opt-recursive-args ...))
#f
#f

View File

@ -1,7 +1,7 @@
#lang scheme/base
;; Foreign Scheme interface
(require '#%foreign setup/dirs
(require '#%foreign setup/dirs scheme/unsafe/ops
(for-syntax scheme/base scheme/list syntax/stx))
;; This module is full of unsafe bindings that are not provided to requiring
@ -1081,7 +1081,8 @@
[TAG-set! (id "" "-set!")]
[_TAG (id "_" "")]
[_TAG* (id "_" "*")]
[TAGname name])
[TAGname name]
[f64? (if (eq? (syntax-e #'TAG) 'f64) #'#t #'#f)])
#'(begin
(define-struct TAG (ptr length))
(provide TAG? TAG-length (rename-out [TAG s:TAG]))
@ -1102,14 +1103,19 @@
(define* (TAG-ref v i)
(if (TAG? v)
(if (and (exact-nonnegative-integer? i) (< i (TAG-length v)))
(ptr-ref (TAG-ptr v) type i)
(if f64? ;; use JIT-inlined operation
(unsafe-f64vector-ref v i)
(ptr-ref (TAG-ptr v) type i))
(error 'TAG-ref "bad index ~e for ~a bounds of 0..~e"
i 'TAG (sub1 (TAG-length v))))
(raise-type-error 'TAG-ref TAGname v)))
(define* (TAG-set! v i x)
(if (TAG? v)
(if (and (exact-nonnegative-integer? i) (< i (TAG-length v)))
(ptr-set! (TAG-ptr v) type i x)
(if (and f64? ;; use JIT-inlined operation
(inexact-real? x))
(unsafe-f64vector-set! v i x)
(ptr-set! (TAG-ptr v) type i x))
(error 'TAG-set! "bad index ~e for ~a bounds of 0..~e"
i 'TAG (sub1 (TAG-length v))))
(raise-type-error 'TAG-set! TAGname v)))
@ -1264,9 +1270,10 @@
(raise-type-error 'cast "ctype" to-type))
(unless (= (ctype-sizeof to-type)
(ctype-sizeof from-type))
(raise-mismatch-error (format "representation sizes of types differ: ~e to "
from-type)
to-type))
(raise-mismatch-error 'cast
(format "representation sizes of from and to types differ: ~e and "
(ctype-sizeof from-type))
(ctype-sizeof to-type)))
(let ([p2 (malloc from-type)])
(ptr-set! p2 from-type p)
(ptr-ref p2 to-type)))

View File

@ -16,7 +16,7 @@
"private/old-procs.ss"
"private/map.ss" ; shadows #%kernel bindings
"private/kernstruct.ss"
"promise.ss"
"private/promise.ss"
(only "private/cond.ss" old-cond)
"tcp.ss"
"udp.ss"

View File

@ -317,9 +317,11 @@
(let* ([def-ctx (if star?
(syntax-local-make-definition-context (car def-ctxes))
(last def-ctxes))]
[ids (if star?
(map (add-package-context (list def-ctx)) ids)
ids)])
[ids (map
(lambda (id) (syntax-property id 'unshadowable #t))
(if star?
(map (add-package-context (list def-ctx)) ids)
ids))])
(syntax-local-bind-syntaxes ids #'rhs def-ctx)
(register-bindings! ids)
(loop (cdr exprs)
@ -335,9 +337,11 @@
(let* ([def-ctx (if star?
(syntax-local-make-definition-context (car def-ctxes))
(last def-ctxes))]
[ids (if star?
(map (add-package-context (list def-ctx)) ids)
ids)])
[ids (map
(lambda (id) (syntax-property id 'unshadowable #t))
(if star?
(map (add-package-context (list def-ctx)) ids)
ids))])
(syntax-local-bind-syntaxes ids #f def-ctx)
(register-bindings! ids)
(loop (cdr exprs)

View File

@ -1,71 +0,0 @@
#lang scheme/base
(require (for-template scheme/base))
(provide at-syntax)
;; -------------------------------------------------------------------
;; NOTE: This library is for internal use only, it is can change
;; and/or disappear. Do not use without protective eyewear!
;; -------------------------------------------------------------------
#|
The `(at-syntax expr)' form is a useful syntax-time utility that can
be used to sort of evaluate an expression at syntax time, and doing so
in a well behaved way (eg, it respects the source for-syntax bindings,
but it does have some issues). It can be used to implement an escape
to the syntax level that is not restricted like `begin-for-syntax'.
The basic idea of the code is to plant the given expression on the
right hand side of a `let-syntax' -- inside a `(lambda (stx) ...)' to
make it a valid transformer, with a singe use of this macro so that we
get it to execute with `local-expand'. The macro returns a 3d
expression that contains the evaluated expression "somehwhere",
depending on the expansion of `let-syntax' -- so to make it easy to
find we plant it inside a thunk (so this works as long as `let-syntax'
does not include 3d procedure values in its expansion). Finally, the
constructed `let-syntax' is expanded, we search through the resulting
syntax for the thunk, then apply it to get the desired value.
Here's a silly example to demonstrate:
> (define-syntax (compile-time-if stx)
(syntax-case stx ()
[(_ cond expr1 expr2)
(if (at-syntax #'cond) #'expr1 #'expr2)]))
> (define-for-syntax x 8)
> (define x 100)
> (compile-time-if (< x 10) (+ x 10) (- x 10))
110
And another example, creating a macro for syntax-time expressions:
> (define-syntax (compile-time-value stx)
(syntax-case stx ()
[(_ expr) #`(quote #,(at-syntax #'expr))]))
> (compile-time-value (* x 2))
16
but the `quote' here is a hint that this can get 3d values into
syntax, and all the problems that are involved. Also, note that it
breaks if you try to do something like:
> (compile-time-value (begin (set! x 11) x))
8
(and, of course, it cannot be used to define new bindings).
|#
(define (at-syntax expr)
(let loop ([x (with-syntax ([e expr])
(local-expand
#'(let-syntax ([here (lambda (stx)
(datum->syntax stx (lambda () e)))])
here)
'expression '()))])
(cond [(procedure? x) (x)]
[(pair? x) (or (loop (car x)) (loop (cdr x)))]
[(syntax? x) (loop (syntax-e x))]
[else #f])))

View File

@ -469,8 +469,8 @@
(define in-port
(case-lambda
[() (in-port (current-input-port) read)]
[(r) (in-port (current-input-port) r)]
[() (in-port read (current-input-port))]
[(r) (in-port r (current-input-port))]
[(r p)
(unless (and (procedure? r) (procedure-arity-includes? r 1))
(raise-type-error 'in-port "procedure (arity 1)" r))

View File

@ -0,0 +1,269 @@
(module promise '#%kernel
(#%require "small-scheme.ss"
"more-scheme.ss"
"define.ss"
(rename "define-struct.ss" define-struct define-struct*)
(for-syntax '#%kernel "stxcase-scheme.ss" "name.ss")
'#%unsafe)
(#%provide force promise? promise-forced? promise-running?
;; provided to create extensions
(struct promise ()) pref pset! prop:force reify-result
promise-printer
(struct running ()) (struct reraise ())
(for-syntax make-delayer))
;; This module implements "lazy" (composable) promises and a `force'
;; that is iterated through them.
;; This is similar to the *new* version of srfi-45 -- see the
;; post-finalization discussion at http://srfi.schemers.org/srfi-45/ for
;; more details; specifically, this version is the `lazy2' version from
;; http://srfi.schemers.org/srfi-45/post-mail-archive/msg00013.html.
;; Note: if you use only `force'+`delay' it behaves as in Scheme (except
;; that `force' is identity for non promise values), and `force'+`lazy'
;; are sufficient for implementing the lazy language.
;; unsafe accessors
(define-syntax pref (syntax-rules () [(_ p ) (unsafe-struct-ref p 0 )]))
(define-syntax pset! (syntax-rules () [(_ p x) (unsafe-struct-set! p 0 x)]))
;; ----------------------------------------------------------------------------
;; Forcers
;; force/composable iterates on composable promises
;; * (force X) = X for non promises
;; * does not deal with multiple values in the composable case
(define (force/composable root)
(let ([v (pref root)])
(cond
[(procedure? v)
;; mark the root as running: avoids cycles, and no need to keep banging
;; the root promise value; it makes this non-r5rs, but the only
;; practical uses of these things could be ones that use state to avoid
;; an infinite loop. (See the generic forcer below.)
;; (careful: avoid holding a reference to the thunk, to allow
;; safe-for-space loops)
(pset! root (make-running (object-name v)))
(call-with-exception-handler
(lambda (e) (pset! root (make-reraise e)) e)
(lambda ()
;; iterate carefully through chains of composable promises
(let loop ([v (v)]) ; does not handle multiple values!
(cond [(composable-promise? v)
(let ([v* (pref v)])
(pset! v root) ; share with root
(cond [(procedure? v*) (loop (v*))]
;; it must be a list of one value (because
;; composable promises never hold multiple values),
;; or a composable promise
[(pair? v*) (pset! root v*) (unsafe-car v*)]
;; note: for the promise case we could jump only to
;; the last `let' (for `v*'), but that makes the
;; code heavier, and runs slower (probably goes over
;; some inlining/unfolding threshold).
[else (loop v*)]))]
;; reached a non-composable promise: share and force it now
[(promise? v) (pset! root v) (force v)]
;; error here for "library approach" (see above URL)
[else (pset! root (list v)) v]))))]
;; try to make the order efficient, with common cases first
[(pair? v) (if (null? (unsafe-cdr v)) (unsafe-car v) (apply values v))]
;; follow all sharings (and shortcut directly to the right force)
[(composable-promise? v) (force/composable v) (force v)]
[(null? v) (values)]
[else (error 'force "composable promise with invalid contents: ~e" v)])))
(define (reify-result v)
(cond [(pair? v) (if (null? (unsafe-cdr v)) (unsafe-car v) (apply values v))]
[(null? v) (values)]
[(reraise? v) (v)]
[else (error 'force "promise with invalid contents: ~e" v)]))
;; generic force for "old-style" promises -- they're still useful in
;; that they allow multiple values. In general, this is slower, but has
;; more features. (They could allow self loops, but this means holding
;; on to the procedure and its resources while it is running, and lose
;; the ability to know that it is running; the second can be resolved
;; with a new kind of `running' value that can be used again, but the
;; first cannot be solved. I still didn't ever see any use for them, so
;; they're still forbidden.)
(define (force/generic promise)
(reify-result
(let ([v (pref promise)])
(if (procedure? v)
(begin
(pset! promise (make-running (object-name v)))
(call-with-exception-handler
(lambda (e) (pset! promise (make-reraise e)) e)
(lambda ()
(let ([vs (call-with-values v list)]) (pset! promise vs) vs))))
v))))
;; dispatcher for composable promises, generic promises, and other values
(define (force promise)
(if (promise? promise)
((promise-forcer promise) promise) ; dispatch to specific forcer
promise)) ; different from srfi-45: identity for non-promises
;; ----------------------------------------------------------------------------
;; Struct definitions
;; generic promise printer
(define (promise-printer promise port write?)
(let loop ([v (pref promise)])
(cond
[(reraise? v)
(let ([r (reraise-val v)])
(if (exn? r)
(fprintf port (if write? "#<promise!exn!~s>" "#<promise!exn!~a>")
(exn-message r))
(fprintf port (if write? "#<promise!raise!~s>" "#<promise!raise!~a>")
r)))]
[(running? v)
(let ([r (running-name v)])
(if r
(fprintf port "#<promise:!running!~a>" r)
(fprintf port "#<promise:!running>")))]
[(procedure? v)
(cond [(object-name v)
=> (lambda (n) (fprintf port "#<promise:~a>" n))]
[else (display "#<promise>" port)])]
[(promise? v) (loop (pref v))] ; hide sharing
;; values
[(null? v) (fprintf port "#<promise!(values)>")]
[(null? (cdr v))
(fprintf port (if write? "#<promise!~s>" "#<promise!~a>") (car v))]
[else (display "#<promise!(values" port)
(let ([fmt (if write? " ~s" " ~a")])
(for-each (lambda (x) (fprintf port fmt x)) v))
(display ")>" port)])))
;; property value for the right forcer to use
(define-values [prop:force promise-forcer]
(let-values ([(prop pred? get) ; no need for the predicate
(make-struct-type-property 'forcer
(lambda (v info)
(unless (and (procedure? v)
(procedure-arity-includes? v 1))
(raise-type-error 'prop:force "a unary function" v))
v))])
(values prop get)))
;; A promise value can hold
;; - (list <value> ...): forced promise (possibly multiple-values)
;; - composable promises deal with only one value
;; - <promise>: a shared (redirected) promise that points at another one
;; - possible only with composable promises
;; - <thunk>: usually a delayed promise,
;; - can also hold a `running' thunk that will throw a reentrant error
;; - can also hold a raising-a-value thunk on exceptions and other
;; `raise'd values (actually, applicable structs for printouts)
;; First, a generic struct, which is used for all promise-like values
(define-struct promise ([val #:mutable])
#:property prop:custom-write promise-printer
#:property prop:force force/generic)
;; Then, a subtype for composable promises
(define-struct (composable-promise promise) ()
#:property prop:force force/composable)
;; template for all delay-like constructs
;; (with simple keyword matching: keywords is an alist with default exprs)
(define-for-syntax (make-delayer stx maker keywords)
;; no `cond', `and', `or', `let', `define', etc here
(letrec-values
([(exprs+kwds)
(lambda (stxs exprs kwds)
(if (null? stxs)
(values (reverse exprs) (reverse kwds))
(if (not (keyword? (syntax-e (car stxs))))
(exprs+kwds (cdr stxs) (cons (car stxs) exprs) kwds)
(if (if (pair? (cdr stxs))
(if (assq (syntax-e (car stxs)) keywords)
(not (assq (syntax-e (car stxs)) kwds))
#f)
#f)
(exprs+kwds (cddr stxs) exprs
(cons (cons (syntax-e (car stxs)) (cadr stxs))
kwds))
(values #f #f)))))]
[(stxs) (syntax->list stx)]
[(exprs kwds) (exprs+kwds (if stxs (cdr stxs) '()) '() '())]
[(kwd-args) (if kwds
(map (lambda (k)
(let-values ([(x) (assq (car k) kwds)])
(if x (cdr x) (cdr k))))
keywords)
#f)]
;; some strange bug with `syntax-local-expand-expression' makes this not
;; work well with identifiers, so turn the name into a symbol to work
;; around this for now
[(name0) (syntax-local-infer-name stx)]
[(name) (if (syntax? name0) (syntax-e name0) name0)])
(syntax-case stx ()
[_ (pair? exprs) ; throw a syntax error if anything is wrong
(with-syntax ([(expr ...) exprs]
[(kwd-arg ...) kwd-args])
(with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr ...))
'inferred-name name)]
[make maker])
(syntax/loc stx (make proc kwd-arg ...))))])))
;; Creates a composable promise
;; X = (force (lazy X)) = (force (lazy (lazy X))) = (force (lazy^n X))
(#%provide (rename lazy* lazy))
(define lazy make-composable-promise)
(define-syntax (lazy* stx) (make-delayer stx #'lazy '()))
;; Creates a (generic) promise that does not compose
;; X = (force (delay X)) = (force (lazy (delay X)))
;; = (force (lazy^n (delay X)))
;; X = (force (force (delay (delay X)))) != (force (delay (delay X)))
;; so each sequence of `(lazy^n o delay)^m' requires m `force's and a
;; sequence of `(lazy^n o delay)^m o lazy^k' requires m+1 `force's (for k>0)
;; (This is not needed with a lazy language (see the above URL for details),
;; but provided for regular delay/force uses.)
(#%provide (rename delay* delay))
(define delay make-promise)
(define-syntax (delay* stx) (make-delayer stx #'delay '()))
;; For simplicity and efficiency this code uses thunks in promise values for
;; exceptions: this way, we don't need to tag exception values in some special
;; way and test for them -- we just use a thunk that will raise the exception.
;; But it's still useful to refer to the exception value, so use an applicable
;; struct for them. The same goes for a promise that is being forced: we use a
;; thunk that will throw a "reentrant promise" error -- and use an applicable
;; struct so it is identifiable.
(define-struct reraise (val)
#:property prop:procedure (lambda (this) (raise (reraise-val this))))
(define-struct running (name)
#:property prop:procedure (lambda (this)
(let ([name (running-name this)])
(if name
(error 'force "reentrant promise ~e" name)
(error 'force "reentrant promise")))))
;; ----------------------------------------------------------------------------
;; Utilities
(define (promise-forced? promise)
(if (promise? promise)
(let ([v (pref promise)])
(or (not (procedure? v)) (reraise? v))) ; #f when running
(raise-type-error 'promise-forced? "promise" promise)))
(define (promise-running? promise)
(if (promise? promise)
(running? (pref promise))
(raise-type-error 'promise-running? "promise" promise)))
)
#|
Simple code for timings:
(define (c n) (lazy (if (zero? n) (delay 'hey!) (c (sub1 n)))))
(for ([i (in-range 9)])
(collect-garbage) (collect-garbage) (collect-garbage)
(time (for ([i (in-range 10000)]) (force (c 2000)))))
Also, run (force (c -1)) and check constant space
|#

View File

@ -76,14 +76,16 @@ doing these checks.
(loop a1 b1 c1)))))))))
(define-syntax-rule (copying-insertionsort Alo Blo n)
(let iloop ([i 0] [A Alo])
(when (i< i n)
(let ([ref-i (ref A)])
(let jloop ([j (i+ Blo i)])
(let ([ref-j-1 (ref (i- j 1))])
(if (and (i< Blo j) (<? ref-i ref-j-1))
(begin (set! j ref-j-1) (jloop (i- j 1)))
(begin (set! j ref-i) (iloop (i+ i 1) (i+ A 1))))))))))
;; n is never 0
(begin (set! Blo (ref Alo))
(let iloop ([i 1])
(when (i< i n)
(let ([ref-i (ref (i+ Alo i))])
(let jloop ([j (i+ Blo i)])
(let ([ref-j-1 (ref (i- j 1))])
(if (and (i< Blo j) (<? ref-i ref-j-1))
(begin (set! j ref-j-1) (jloop (i- j 1)))
(begin (set! j ref-i) (iloop (i+ i 1)))))))))))
(define (copying-mergesort Alo Blo n)
(cond

View File

@ -1,257 +1,6 @@
(module promise '#%kernel
(#%require "private/small-scheme.ss"
"private/more-scheme.ss"
"private/define.ss"
(rename "private/define-struct.ss" define-struct define-struct*)
(for-syntax '#%kernel "private/stxcase-scheme.ss" "private/name.ss")
'#%unsafe)
(#%provide force promise? promise-forced? promise-running?)
;; This module implements "lazy" (composable) promises and a `force'
;; that is iterated through them.
;; This is similar to the *new* version of srfi-45 -- see the
;; post-finalization discussion at http://srfi.schemers.org/srfi-45/ for
;; more details; specifically, this version is the `lazy2' version from
;; http://srfi.schemers.org/srfi-45/post-mail-archive/msg00013.html.
;; Note: if you use only `force'+`delay' it behaves as in Scheme (except
;; that `force' is identity for non promise values), and `force'+`lazy'
;; are sufficient for implementing the lazy language.
;; unsafe accessors
(define-syntax pref (syntax-rules () [(_ p) (unsafe-struct-ref p 0)]))
(define-syntax pset! (syntax-rules () [(_ p x) (unsafe-struct-set! p 0 x)]))
;; ----------------------------------------------------------------------------
;; Forcers
;; force/composable iterates on composable promises
;; * (force X) = X for non promises
;; * does not deal with multiple values in the composable case
(define (force/composable root)
(let ([v (pref root)])
(cond
[(procedure? v)
;; mark the root as running: avoids cycles, and no need to keep banging
;; the root promise value; it makes this non-r5rs, but the only
;; practical uses of these things could be ones that use state to avoid
;; an infinite loop. (See the generic forcer below.)
;; (careful: avoid holding a reference to the thunk, to allow
;; safe-for-space loops)
(pset! root (make-running (object-name v)))
(call-with-exception-handler
(lambda (e) (pset! root (make-reraise e)) e)
(lambda ()
;; iterate carefully through chains of composable promises
(let loop ([v (v)]) ; does not handle multiple values!
(cond [(composable-promise? v)
(let ([v* (pref v)])
(pset! v root) ; share with root
(cond [(procedure? v*) (loop (v*))]
;; it must be a list of one value (because
;; composable promises never hold multiple values),
;; or a composable promise
[(pair? v*) (pset! root v*) (unsafe-car v*)]
;; note: for the promise case we could jump only to
;; the last `let' (for `v*'), but that makes the
;; code heavier, and runs slower (probably goes over
;; some inlining/unfolding threshold).
[else (loop v*)]))]
;; reached a non-composable promise: share and force it now
[(promise? v) (pset! root v) (force v)]
;; error here for "library approach" (see above URL)
[else (pset! root (list v)) v]))))]
;; try to make the order efficient, with common cases first
[(pair? v) (if (null? (unsafe-cdr v)) (unsafe-car v) (apply values v))]
;; follow all sharings (and shortcut directly to the right force)
[(composable-promise? v) (force/composable v) (force v)]
[(null? v) (values)]
[else (error 'force "composable promise with invalid contents: ~e" v)])))
(define (reify-result v)
(cond
[(pair? v) (if (null? (unsafe-cdr v)) (unsafe-car v) (apply values v))]
[(null? v) (values)]
[(reraise? v) (v)]
[else (error 'force "promise with invalid contents: ~e" v)]))
;; generic force for "old-style" promises -- they're still useful in
;; that they allow multiple values. In general, this is slower, but has
;; more features. (They could allow self loops, but this means holding
;; on to the procedure and its resources while it is running, and lose
;; the ability to know that it is running; the second can be resolved
;; with a new kind of `running' value that can be used again, but the
;; first cannot be solved. I still didn't ever see any use for them, so
;; they're still forbidden.)
(define (force/generic promise)
(reify-result
(let ([v (pref promise)])
(if (procedure? v)
(begin
(pset! promise (make-running (object-name v)))
(call-with-exception-handler
(lambda (e) (pset! promise (make-reraise e)) e)
(lambda ()
(let ([vs (call-with-values v list)]) (pset! promise vs) vs))))
v))))
;; dispatcher for composable promises, generic promises, and other values
(define (force promise)
(if (promise? promise)
((promise-forcer promise) promise) ; dispatch to specific forcer
promise)) ; different from srfi-45: identity for non-promises
;; ----------------------------------------------------------------------------
;; Struct definitions
;; generic promise printer
(define (promise-printer promise port write?)
(let loop ([v (pref promise)])
(cond
[(reraise? v)
(let ([r (reraise-val v)])
(if (exn? r)
(fprintf port (if write? "#<promise!exn!~s>" "#<promise!exn!~a>")
(exn-message r))
(fprintf port (if write? "#<promise!raise!~s>" "#<promise!raise!~a>")
r)))]
[(running? v)
(let ([r (running-name v)])
(if r
(fprintf port "#<promise:!running!~a>" r)
(fprintf port "#<promise:!running>")))]
[(procedure? v)
(cond [(object-name v)
=> (lambda (n) (fprintf port "#<promise:~a>" n))]
[else (display "#<promise>" port)])]
[(promise? v) (loop (pref v))] ; hide sharing
;; values
[(null? v) (fprintf port "#<promise!(values)>")]
[(null? (cdr v))
(fprintf port (if write? "#<promise!~s>" "#<promise!~a>") (car v))]
[else (display "#<promise!(values" port)
(let ([fmt (if write? " ~s" " ~a")])
(for-each (lambda (x) (fprintf port fmt x)) v))
(display ")>" port)])))
;; property value for the right forcer to use
(define-values [prop:force promise-forcer]
(let-values ([(prop pred? get) ; no need for the predicate
(make-struct-type-property 'forcer
(lambda (v info)
(unless (and (procedure? v)
(procedure-arity-includes? v 1))
(raise-type-error 'prop:force "a unary function" v))
v))])
(values prop get)))
;; A promise value can hold
;; - (list <value> ...): forced promise (possibly multiple-values)
;; - composable promises deal with only one value
;; - <promise>: a shared (redirected) promise that points at another one
;; - possible only with composable promises
;; - <thunk>: usually a delayed promise,
;; - can also hold a `running' thunk that will throw a reentrant error
;; - can also hold a raising-a-value thunk on exceptions and other
;; `raise'd values (actually, applicable structs for printouts)
;; First, a generic struct, which is used for all promise-like values
(define-struct promise ([val #:mutable])
#:property prop:custom-write promise-printer
#:property prop:force force/generic)
;; Then, a subtype for composable promises
(define-struct (composable-promise promise) ()
#:property prop:force force/composable)
;; template for all delay-like constructs
;; (with simple keyword matching: keywords is an alist with default exprs)
(define-for-syntax (make-delayer stx maker keywords)
;; no `cond', `and', `or', `let', `define', etc here
(letrec-values
([(exprs+kwds)
(lambda (stxs exprs kwds)
(if (null? stxs)
(values (reverse exprs) (reverse kwds))
(if (not (keyword? (syntax-e (car stxs))))
(exprs+kwds (cdr stxs) (cons (car stxs) exprs) kwds)
(if (if (pair? (cdr stxs))
(if (assq (syntax-e (car stxs)) keywords)
(not (assq (syntax-e (car stxs)) kwds))
#f)
#f)
(exprs+kwds (cddr stxs) exprs
(cons (cons (syntax-e (car stxs)) (cadr stxs))
kwds))
(values #f #f)))))]
[(stxs) (syntax->list stx)]
[(exprs kwds) (exprs+kwds (if stxs (cdr stxs) '()) '() '())]
[(kwd-args) (if kwds
(map (lambda (k)
(let-values ([(x) (assq (car k) kwds)])
(if x (cdr x) (cdr k))))
keywords)
#f)]
;; some strange bug with `syntax-local-expand-expression' makes this not
;; work well with identifiers, so turn the name into a symbol to work
;; around this for now
[(name0) (syntax-local-infer-name stx)]
[(name) (if (syntax? name0) (syntax-e name0) name0)])
(syntax-case stx ()
[_ (pair? exprs) ; throw a syntax error if anything is wrong
(with-syntax ([(expr ...) exprs]
[(kwd-arg ...) kwd-args])
(with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr ...))
'inferred-name name)]
[make maker])
(syntax/loc stx (make proc kwd-arg ...))))])))
;; Creates a composable promise
;; X = (force (lazy X)) = (force (lazy (lazy X))) = (force (lazy^n X))
(#%provide (rename lazy* lazy))
(define lazy make-composable-promise)
(define-syntax (lazy* stx) (make-delayer stx #'lazy '()))
;; Creates a (generic) promise that does not compose
;; X = (force (delay X)) = (force (lazy (delay X)))
;; = (force (lazy^n (delay X)))
;; X = (force (force (delay (delay X)))) != (force (delay (delay X)))
;; so each sequence of `(lazy^n o delay)^m' requires m `force's and a
;; sequence of `(lazy^n o delay)^m o lazy^k' requires m+1 `force's (for k>0)
;; (This is not needed with a lazy language (see the above URL for details),
;; but provided for regular delay/force uses.)
(#%provide (rename delay* delay))
(define delay make-promise)
(define-syntax (delay* stx) (make-delayer stx #'delay '()))
;; For simplicity and efficiency this code uses thunks in promise values for
;; exceptions: this way, we don't need to tag exception values in some special
;; way and test for them -- we just use a thunk that will raise the exception.
;; But it's still useful to refer to the exception value, so use an applicable
;; struct for them. The same goes for a promise that is being forced: we use a
;; thunk that will throw a "reentrant promise" error -- and use an applicable
;; struct so it is identifiable.
(define-struct reraise (val)
#:property prop:procedure (lambda (this) (raise (reraise-val this))))
(define-struct running (name)
#:property prop:procedure (lambda (this)
(let ([name (running-name this)])
(if name
(error 'force "reentrant promise ~e" name)
(error 'force "reentrant promise")))))
;; ----------------------------------------------------------------------------
;; Utilities
(define (promise-forced? promise)
(if (promise? promise)
(let ([v (pref promise)])
(or (not (procedure? v)) (reraise? v))) ; #f when running
(raise-type-error 'promise-forced? "promise" promise)))
(define (promise-running? promise)
(if (promise? promise)
(running? (pref promise))
(raise-type-error 'promise-running? "promise" promise)))
#lang scheme/base
(require "private/promise.ss" (for-syntax scheme/base))
(provide delay lazy force promise? promise-forced? promise-running?)
;; ----------------------------------------------------------------------------
;; More delay-like values, with different ways of deferring computations
@ -259,7 +8,7 @@
(define-struct (promise/name promise) ()
#:property prop:force (lambda (p) ((pref p))))
(#%provide (rename delay/name* delay/name))
(provide (rename-out [delay/name* delay/name]))
(define delay/name make-promise/name)
(define-syntax (delay/name* stx) (make-delayer stx #'delay/name '()))
@ -315,7 +64,7 @@
(let ([v (pref p)])
(handle-evt (if (syncinfo? v) (syncinfo-done-evt v) always-evt) void))))
(#%provide (rename delay/sync* delay/sync))
(provide (rename-out [delay/sync* delay/sync]))
(define (delay/sync thunk)
(let ([done-sema (make-semaphore 0)])
(make-promise/sync (make-syncinfo thunk
@ -339,7 +88,7 @@
(handle-evt (if (running? v) (running-thread-thread v) always-evt)
void))))
(#%provide (rename delay/thread* delay/thread))
(provide (rename-out [delay/thread* delay/thread]))
(define (delay/thread thunk group)
(define (run)
(call-with-exception-handler
@ -354,7 +103,7 @@
(thread run)))))
p)
(define-syntax delay/thread*
(let-values ([(kwds) (list (cons '#:group #'#t))])
(let ([kwds (list (cons '#:group #'#t))])
(lambda (stx) (make-delayer stx #'delay/thread kwds))))
(define-struct (promise/idle promise/thread) ()
@ -371,7 +120,7 @@
(pref p))
v)))))
(#%provide (rename delay/idle* delay/idle))
(provide (rename-out [delay/idle* delay/idle]))
(define (delay/idle thunk wait-for work-while tick use*)
(define use (cond [(use* . <= . 0) 0] [(use* . >= . 1) 1] [else use*]))
(define work-time (* tick use))
@ -422,19 +171,8 @@
(or (object-name thunk) 'idle-thread))))
p)
(define-syntax delay/idle*
(let-values ([(kwds) (list (cons '#:wait-for #'(system-idle-evt))
(cons '#:work-while #'(system-idle-evt))
(cons '#:tick #'0.2)
(cons '#:use #'0.12))])
(let ([kwds (list (cons '#:wait-for #'(system-idle-evt))
(cons '#:work-while #'(system-idle-evt))
(cons '#:tick #'0.2)
(cons '#:use #'0.12))])
(lambda (stx) (make-delayer stx #'delay/idle kwds))))
)
#|
Simple code for timings:
(define (c n) (lazy (if (zero? n) (delay 'hey!) (c (sub1 n)))))
(for ([i (in-range 9)])
(collect-garbage) (collect-garbage) (collect-garbage)
(time (for ([i (in-range 10000)]) (force (c 2000)))))
Also, run (force (c -1)) and check constant space
|#

View File

@ -1,7 +1,7 @@
#lang scheme/base
(require (for-syntax scheme/base scheme/provide-transform scheme/list
"private/at-syntax.ss"))
(only-in unstable/syntax syntax-local-eval)))
(provide matching-identifiers-out)
(define-syntax matching-identifiers-out
@ -21,7 +21,7 @@
(lambda (stx modes)
(syntax-case stx ()
[(_ proc spec)
(let ([proc (at-syntax #'proc)])
(let ([proc (syntax-local-eval #'proc)])
(filter-map
(lambda (e)
(let* ([s1 (symbol->string (export-out-sym e))]

View File

@ -1,7 +1,7 @@
#lang scheme/base
(require (for-syntax scheme/base scheme/require-transform scheme/list
"private/at-syntax.ss")
(only-in unstable/syntax syntax-local-eval))
"require-syntax.ss")
(provide matching-identifiers-in)
@ -43,7 +43,7 @@
(lambda (stx)
(syntax-case stx ()
[(_ proc spec)
(let ([proc (at-syntax #'proc)])
(let ([proc (syntax-local-eval #'proc)])
(define-values [imports sources] (expand-import #'spec))
(values
(filter-map

View File

@ -1,6 +1,7 @@
#lang scheme/base
(require scheme/unit
scheme/contract
(for-syntax scheme/base
mzlib/private/unit-compiletime
mzlib/private/unit-syntax))
@ -8,6 +9,7 @@
(provide (rename-out [module-begin #%module-begin])
(except-out (all-from-out scheme/base) #%module-begin)
(all-from-out scheme/unit)
(all-from-out scheme/contract)
(for-syntax (all-from-out scheme/base)))
(define-for-syntax (make-name s)

View File

@ -619,7 +619,7 @@
,@(navigation d ri #t)
,@(render-part d ri)
,@(navigation d ri #f)))
(div ([id "langindicator"]) nbsp)))))))))
(div ([id "contextindicator"]) nbsp)))))))))
(define/private (part-parent d ri)
(collected-info-parent (part-collected-info d ri)))

View File

@ -7,14 +7,14 @@
(provide lp-include)
(define-syntax (module stx)
(syntax-case stx ()
(syntax-case stx (#%module-begin)
[(module name base (#%module-begin body ...))
#'(begin body ...)]
[(module name base body ...)
(begin
#'(begin body ...))]))
(raise-syntax-error #f "missing #%module-begin" stx)]))
(define-syntax (lp-include stx)
(syntax-case stx ()
[(_ name)
(with-syntax ([there (datum->syntax stx 'there)])
#'(include-at/relative-to here there name))]))

View File

@ -1,5 +1,56 @@
// Common functionality for PLT documentation pages
// Page Parameters ------------------------------------------------------------
var page_query_string =
(location.href.search(/\?([^#]+)(?:#|$)/) >= 0) && RegExp.$1;
var page_args =
((function(){
if (!page_query_string) return [];
var args = page_query_string.split(/[&;]/);
for (var i=0; i<args.length; i++) {
var a = args[i];
var p = a.indexOf('=');
if (p >= 0) args[i] = [a.substring(0,p), a.substring(p+1)];
else args[i] = [a, false];
}
return args;
})());
function GetPageArg(key, def) {
for (var i=0; i<page_args.length; i++)
if (page_args[i][0] == key) return unescape(page_args[i][1]);
return def;
}
function MergePageArgsIntoLink(a) {
if (page_args.length == 0 ||
(!a.attributes["pltdoc"]) || (a.attributes["pltdoc"].value == ""))
return;
a.href.search(/^([^?#]*)(?:\?([^#]*))?(#.*)?$/);
if (RegExp.$2.length == 0) {
a.href = RegExp.$1 + "?" + page_query_string + RegExp.$3;
} else {
// need to merge here, precedence to arguments that exist in `a'
var i, j;
var prefix = RegExp.$1, str = RegExp.$2, suffix = RegExp.$3;
var args = str.split(/[&;]/);
for (i=0; i<args.length; i++) {
j = args[i].indexOf('=');
if (j) args[i] = args[i].substring(0,j);
}
var additions = "";
for (i=0; i<page_args.length; i++) {
var exists = false;
for (j=0; j<args.length; j++)
if (args[j] == page_args[i][0]) { exists = true; break; }
if (!exists) str += "&" + page_args[i][0] + "=" + page_args[i][1];
}
a.href = prefix + "?" + str + suffix;
}
}
// Cookies --------------------------------------------------------------------
function GetCookie(key, def) {
@ -38,38 +89,6 @@ function GotoPLTRoot(ver, relative) {
return false;
}
// URL Parameters -------------------------------------------------------------
// In the following functions, the `name' argument is assumed to be simple in
// that it doesn't contain anything that isn't plain text in a regexp. (This
// is because JS doesn't have a `regexp-quote', easy to hack but not needed
// here). Also, the output value from the Get functions and the input value to
// the Set functions is decoded/encoded. Note that `SetArgInURL' mutates the
// string in the url object.
function GetArgFromString(str, name) {
var rx = new RegExp("(?:^|[;&])"+name+"=([^&;]*)(?:[;&]|$)");
return rx.test(str) && unescape(RegExp.$1);
}
function SetArgInString(str, name, val) {
val = escape(val);
if (str.length == 0) return name + "=" + val;
var rx = new RegExp("^((?:|.*[;&])"+name+"=)(?:[^&;]*)([;&].*|)$");
if (rx.test(str)) return RegExp.$1 + val + RegExp.$2;
else return name + "=" + val + "&" + str;
}
function GetArgFromURL(url, name) {
if (!url.href.search(/\?([^#]*)(?:#|$)/)) return false;
return GetArgFromString(RegExp.$1, name);
}
function SetArgInURL(url, name, val) { // note: mutates the string
url.href.search(/^([^?#]*)(?:\?([^#]*))?(#.*)?$/);
url.href = RegExp.$1 + "?" + SetArgInString(RegExp.$2,name,val) + RegExp.$3;
}
// Utilities ------------------------------------------------------------------
normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/];
@ -91,7 +110,9 @@ function DoSearchKey(event, field, ver, top_path) {
if (event && event.keyCode == 13) {
var u = GetCookie("PLT_Root."+ver, null);
if (u == null) u = top_path; // default: go to the top path
location = u + "search/index.html" + "?q=" + escape(val);
u += "search/index.html?q=" + escape(val);
if (page_query_string) u += "&" + page_query_string;
location = u;
return false;
}
return true;
@ -115,23 +136,13 @@ window.onload = function() {
for (var i=0; i<on_load_funcs.length; i++) on_load_funcs[i]();
};
var cur_plt_lang = GetArgFromURL(location,"lang");
function PropagateLangInLink(a) {
// the attribute's value doesn't matter
if (cur_plt_lang
&& a.attributes["pltdoc"] && a.attributes["pltdoc"].value != ""
&& !GetArgFromURL(a,"lang"))
SetArgInURL(a, "lang", cur_plt_lang);
}
AddOnLoad(function(){
if (!cur_plt_lang) return;
var indicator = document.getElementById("langindicator");
if (indicator) {
indicator.innerHTML = cur_plt_lang;
indicator.style.display = "block";
}
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) PropagateLangInLink(links[i]);
for (var i=0; i<links.length; i++) MergePageArgsIntoLink(links[i]);
var label = GetPageArg("ctxtname",false);
if (!label) return;
var indicator = document.getElementById("contextindicator");
if (!indicator) return;
indicator.innerHTML = label;
indicator.style.display = "block";
});

View File

@ -119,7 +119,7 @@ table td {
vertical-align: middle;
}
#langindicator {
#contextindicator {
position: fixed;
background-color: #c6f;
color: #000;

View File

@ -470,6 +470,15 @@ form, only the input @scheme[type-expr]s and the output @scheme[type-expr] are
specified, and each types is a simple expression, which creates a
straightforward function type.
For instance,
@schemeblock[
(_fun _int _string -> _int)
]
specifies a function that receives an integer and a
string, and returns an integer.
In its full form, the @scheme[_fun] syntax provides an IDL-like
language that can be used to create a wrapper function around the
primitive foreign function. These wrappers can implement complex

View File

@ -7,35 +7,158 @@
@(require scribble/manual
scribble/urls
scribble/struct
(for-label scheme/base
(for-label scheme
scheme/base
scheme/contract
scheme/future))
@; ----------------------------------------------------------------------
PLT's parallel-future support is only enabled if you pass
@DFlag{enable-futures} to @exec{configure} when you build PLT (and
that build currently only works with @exec{mzscheme}, not with
@exec{mred}). When parallel-future support is not enabled,
@scheme[future] just remembers the given thunk to call sequentially
on a later @scheme[touch].
The PLT futures API enables the development of parallel programs which
take advantage of machines with multiple processors, cores, or
hardware threads.
@defmodule[scheme/future]{}
@defproc[(future [thunk (-> any)]) future?]{
Starts running @scheme[thunk] in parallel.
Starts running @scheme[thunk] in parallel. The @scheme[future]
procedure returns immediately with a future descriptor value.
}
@defproc[(touch [f future?]) any]{
Returns the value computed in the future @scheme[f], blocking
to let it complete if it hasn't yet completed.
Returns the value computed in the future @scheme[f], blocking until
the future completes (if it has not already completed).
}
@defproc[(future? [x any/c]) boolean?]{
Returns @scheme[#t] if @scheme[x] is a future.
Returns @scheme[#t] if @scheme[x] is a future.
}
@defproc[(processor-count) exact-positive-integer?]{
Returns the number of processors available on the current system.
Returns the number of processors/cores/hardware threads available on
the current system.
}
@section[#:tag "besteffortpar"]{Best-Effort Parallelism}
The @scheme[future] API represents a best-effort attempt to execute an
arbitrary segment of code in parallel. When designing programs and
algorithms which leverage @scheme[future] for parallel speedup, there
are a number of performance considerations to be aware of.
Futures are designed to accommodate the fact that many low-level
functions provided by the MzScheme virtual machine are not reentrant.
Thus, a future will execute its work in parallel until it detects an
attempt to perform an ``unsafe'' operation (e.g. invoking a
non-reentrant function). When such an operation is detected, the
future will block until @scheme[touch]ed, upon which the remainder of
its work will be done sequentially with respect to the touching
thread (in this case, ``thread'' refers to an OS thread).
To guarantee that unsafe operations never execute simultaneously, only
the initial OS thread used to start the MzScheme virtual machine (the
``runtime thread'') is allowed to execute them. If a parallel future
detects an attempted unsafe operation, it will signal the runtime
thread that pending unsafe work is available, then block, waiting for
the runtime thread to complete it. Note that as mentioned above, the
runtime thread will not attempt to do this work until the future is
explicitly touched. Also note that calls to @scheme[future] and
@scheme[touch] are themselves considered unsafe operations.
Consider the following contrived example:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future (lambda () (+ a b)))])
(touch f)))
(add-in-parallel 4 8)
]
The output of this program is, as expected:
@verbatim|{
12
}|
Now suppose we add a print message to our function for debugging purposes:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future
(lambda ()
(begin
(printf "Adding ~a and ~a together!~n" a b)
(+ a b))))])
(printf "About to touch my future...~n")
(touch f)))
(add-in-parallel 4 8)
]
Though this program still produces the same output, no work is being
done in parallel. Because @scheme[printf] is considered an unsafe
operation, f will block, and the print invocation (along with the
subsequent add) will not be performed until the @scheme[touch] call.
@section[#:tag "logging"]{How Do I Keep Those Cores Busy?}
It is not always obvious when or where unsafe operations may
be causing unacceptable performance degradation in parallel programs.
A a general guideline, any primitive that is inlined will run in parallel.
For example, fixnum and flonum addition do run in parallel,
but not bignum or rational addition. Similarly, vector operations are
generally safe, but not continuation operations. Also, allocation can run
in parallel, as long as only a little bit of allocation happens. Once a significant
amount of allocation happens, a parallel thread has to rendez-vous with the
runtime thread to get new, local memory.
To help tell what is happening in your program, the parallel threads
logs all of the points at which it has to synchronize
with the runtime thread.
For example, running the code in the previous
example in the debug log level produces the following output:
@verbatim|{
About to touch my future...
future: 0 waiting for runtime at 1259702453747.720947: printf
Adding 4 and 8 together!
12
}|
The message indicates which future blocked, the time it blocked and
the primitive operation that caused it to block.
To be sure we are not merely seeing the effects of a race condition in
this example, we can force the main thread to @scheme[sleep] for an
unreasonable amount of time:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future
(lambda ()
(begin
(printf "Adding ~a and ~a together!~n" a b)
(+ a b))))])
(sleep 10.0)
(printf "About to touch my future...~n")
(touch f)))
(add-in-parallel 4 8)
]
@verbatim|{
About to touch my future...
future: 0 waiting for runtime at 1259702453747.720947: printf
Adding 4 and 8 together!
12
}|
@section[#:tag "compiling"]{Enabling Futures in MzScheme Builds}
PLT's parallel-future support is only enabled if you pass
@DFlag{enable-futures} to @exec{configure} when you build PLT (and
that build currently only works with @exec{mzscheme}, not with
@exec{mred}). When parallel-future support is not enabled,
@scheme[future] just remembers the given thunk to call sequentially on
a later @scheme[touch].

View File

@ -1735,7 +1735,7 @@ If @scheme[end] is not @scheme['same] and not the same as @scheme[start],
When the specified range cannot fit in the visible area, @scheme[bias]
indicates which end of the range to display. When @scheme[bias] is
@scheme['same], then the start of the range is displayed. When
@scheme['start], then the start of the range is displayed. When
@scheme[bias] is @scheme['end], then the end of the range is
displayed. Otherwise, @scheme[bias] must be @scheme['none].
@ -1747,7 +1747,7 @@ If the editor is scrolled, then the editor is redrawn and the return
scroll-editor-to].
Scrolling is disallowed when the editor is internally locked for
reflowing (see also @|lockdiscuss|).
reflowing (see also @|lockdiscuss|).
The system may scroll the editor without calling this method. For
example, a canvas displaying an editor might scroll the editor to

View File

@ -253,9 +253,9 @@ machine's instruction to add the numbers (and check for overflow). If
the two numbers are not fixnums, then the next check whether whether
both are flonums; in that case, the machine's floating-point
operations are used directly. For functions that take any number of
arguments, such as @scheme[+], inlining is applied only for the
two-argument case (except for @scheme[-], whose one-argument case is
also inlined).
arguments, such as @scheme[+], inlining works for two or more
arguments (except for @scheme[-], whose one-argument case is also
inlined) when the arguments are either all fixnums or all flonums.
Flonums are @defterm{boxed}, which means that memory is allocated to
hold every result of a flonum computation. Fortunately, the

View File

@ -36,7 +36,6 @@ Creates a new custodian as a subordinate of @var{m}. If @var{m} is
Places the value @var{o} into the management of the custodian
@var{m}. If @var{m} is @cpp{NULL}, the current custodian is used.
The @var{f} function is called by the custodian if it is ever asked to
``shutdown'' its values; @var{o} and @var{data} are passed on to
@var{f}, which has the type
@ -52,6 +51,10 @@ be remembered until either the custodian shuts it down or
zero, the value is allowed to be garbaged collected (and automatically
removed from the custodian).
Independent of whether @var{strong} is zero, the value @var{o} is
initially weakly held. A value associated with a custodian can
therefore be finalized via will executors.
The return value from @cpp{scheme_add_managed} can be used to refer
to the value's custodian later in a call to
@cpp{scheme_remove_managed}. A value can be registered with at

View File

@ -57,6 +57,13 @@ Sets the path to be returned by @scheme[(find-system-path
'collects-dir)].}
@function[(void scheme_set_addon_path
[Scheme_Object* path])]{
Sets the path to be returned by @scheme[(find-system-path
'addon-dir)].}
@function[(void scheme_init_collection_paths_post
[Scheme_Env* env]
[Scheme_Object* pre_extra_paths]

View File

@ -226,7 +226,7 @@ function InitializeSearch() {
result_links.push(n);
AdjustResultsNum();
// get search string
var init_q = GetArgFromURL(location,"q");
var init_q = GetPageArg("q",false);
if (init_q && init_q != "") query.value = init_q;
ContextFilter();
DoSearch();
@ -599,7 +599,7 @@ function UpdateResults() {
if (first_search_result < 0 ||
first_search_result >= search_results.length)
first_search_result = 0;
var link_lang = (cur_plt_lang && ("?lang="+escape(cur_plt_lang)));
var link_args = (page_query_string && ("?"+page_query_string));
for (var i=0; i<result_links.length; i++) {
var n = i + first_search_result;
if (n < search_results.length) {
@ -639,12 +639,12 @@ function UpdateResults() {
if (note)
note = '&nbsp;&nbsp;<span class="smaller">' + note + '</span>';
var href = UncompactUrl(res[1]);
if (link_lang) {
if (link_args) {
var hash = href.indexOf("#");
if (hash >= 0)
href = href.substring(0,hash) + link_lang + href.substring(hash);
href = href.substring(0,hash) + link_args + href.substring(hash);
else
href = href + link_lang;
href = href + link_args;
}
result_links[i].innerHTML =
'<a href="' + href + '" class="indexlink" tabIndex="2">'

View File

@ -33,11 +33,26 @@ scheme
....
]
In general, the @scheme[_rel-string] in @scheme[(lib _rel-string)]
consists of one or more path elements that name collections, and then
a final path element that names a library file; the path elements are
separated by @litchar{/}. If the final element has no file suffix,
then @litchar{/main.ss} is implicitly appended to the path.
This example is more compactly and more commonly written as
@schememod[
scheme
(require setup/getinfo
games/cards/cards)
....
]
When an identifier @scheme[_id] is used in a @scheme[require] form, it
is converted to @scheme[(lib _rel-string)] where @scheme[_rel-string]
is the string form of @scheme[_id].
A @scheme[_rel-string] in @scheme[(lib _rel-string)] consists of one
or more path elements that name collections, and then a final path
element that names a library file; the path elements are separated by
@litchar{/}. If @scheme[_rel-string] contains no @litchar{/}s, then
then @litchar{/main.ss} is implicitly appended to the path. If
@scheme[_rel-string] contains @litchar{/} but does not end with a file
suffix, then @litchar{.ss} is implicitly appended to the path.
The translation of a @scheme[planet] or @scheme[lib] path to a
@scheme[module] declaration is determined by the @tech{module name

View File

@ -1196,8 +1196,8 @@ This property should only be present if the contract is a flat contract. In the
@mz-examples[#:eval (contract-eval)
(flat-pred? (-> integer? integer?))
(let ([c (between/c 1 10)]
[pred ((flat-get c) c)])
(let* ([c (between/c 1 10)]
[pred ((flat-get c) c)])
(list (pred 9)
(pred 11)))]
}

View File

@ -40,8 +40,20 @@ multiple returns/escapes are impossible. All exceptions raised by
Breaks are disabled from the time the exception is raised until the
exception handler obtains control, and the handler itself is
@scheme[parameterize-break]ed to disable breaks initially; see
@secref["breakhandler"] for more information on breaks.}
@secref["breakhandler"] for more information on breaks.
@examples[
(with-handlers ([number? (lambda (n)
(+ n 5))])
(raise 18 #t))
(define-struct (my-exception exn:fail:user) ())
(with-handlers ([my-exception? (lambda (e)
#f)])
(+ 5 (raise (make-my-exception
"failed"
(current-continuation-marks)))))
(raise 'failed #t)
]}
@defproc*[([(error [sym symbol?]) any]
[(error [msg string?][v any/c] ...) any]
@ -72,7 +84,13 @@ ways:
]
In all cases, the constructed message string is passed to
@scheme[make-exn:fail], and the resulting exception is raised.}
@scheme[make-exn:fail], and the resulting exception is raised.
@examples[
(error 'failed)
(error "failed" 23 'pizza (list 1 2 3))
(error 'failed "~a failed because ~a" 'method-a "no argument supplied")
]}
@defproc*[([(raise-user-error [sym symbol?]) any]
[(raise-user-error [msg string?][v any/c] ...) any]
@ -83,7 +101,13 @@ Like @scheme[error], but constructs an exception with
default @tech{error display handler} does not show a ``stack trace'' for
@scheme[exn:fail:user] exceptions (see @secref["contmarks"]), so
@scheme[raise-user-error] should be used for errors that are intended
for end users.}
for end users.
@examples[
(raise-user-error 'failed)
(raise-user-error "failed" 23 'pizza (list 1 2 3))
(raise-user-error 'failed "~a failed because ~a" 'method-a "no argument supplied")
]}
@defproc*[([(raise-type-error [name symbol?][expected string?][v any/c]) any]
@ -102,7 +126,20 @@ In the second form, the bad argument is indicated by an index
arguments @scheme[v] are provided (in order). The resulting error
message names the bad argument and also lists the other arguments. If
@scheme[bad-pos] is not less than the number of @scheme[v]s, the
@exnraise[exn:fail:contract].}
@exnraise[exn:fail:contract].
@examples[
(define (feed-cow animal)
(if (not (eq? animal 'cow))
(raise-type-error 'feed-cow "cow" animal)
"fed the cow"))
(feed-cow 'turkey)
(define (feed-animals cow sheep goose cat)
(if (not (eq? goose 'goose))
(raise-type-error 'feed-animals "goose" 2 cow sheep goose cat)
"fed the animals"))
(feed-animals 'cow 'sheep 'dog 'cat)
]}
@defproc[(raise-mismatch-error [name symbol?][message string?][v any/c]) any]{

View File

@ -80,10 +80,15 @@ by @scheme[kind], which must be one of the following:
]}
@item{@indexed-scheme['addon-dir] --- a directory for installing PLT Scheme
extensions. It's the same as @scheme['pref-dir], except under Mac OS
X, where it is @filepath{Library/PLT Scheme} in the user's home
directory. This directory might not exist.}
@item{@indexed-scheme['addon-dir] --- a directory for installing PLT
Scheme extensions. This directory is specified by the
@indexed-envvar{PLTADDONDIR} environment variable, and it can be
overridden by the @DFlag{addon} or @Flag{A} command-line flag. If no
environment variable or flag is specified, or if the value is not a
legal path name, then this directory defaults to
@filepath{Library/PLT Scheme} in the user's home directory under Mac
OS X and @scheme['pref-dir] otherwise. This directory might not
exist.}
@item{@indexed-scheme['doc-dir] --- the standard directory for
storing the current user's documents. Under Unix, it's the same as
@ -593,17 +598,6 @@ Reads all characters from @scheme[path] and returns them as a
@tech{byte string}. The @scheme[mode-flag] argument is the same as
for @scheme[open-input-file].}
@defproc[(file->lines [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
bytes?]{
Read all characters from @scheme[path], breaking them into lines. The
@scheme[line-mode] argument is the same as the second argument to
@scheme[read-line], but the default is @scheme['any] instead of
@scheme['linefeed]. The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->value [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary])
bytes?]{
@ -612,10 +606,29 @@ Reads a single S-expression from @scheme[path] using @scheme[read].
The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->list [path path-string?]
[proc (input-port? . -> . any/c) read]
[#:mode mode-flag (or/c 'binary 'text) 'binary])
(listof any/c)]{
Repeatedly calls @scheme[proc] to consume the contents of
@scheme[path], until @scheme[eof] is produced. The @scheme[mode-flag]
argument is the same as for @scheme[open-input-file]. }
@defproc[(file->lines [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
(listof string?)]{
Read all characters from @scheme[path], breaking them into lines. The
@scheme[line-mode] argument is the same as the second argument to
@scheme[read-line], but the default is @scheme['any] instead of
@scheme['linefeed]. The @scheme[mode-flag] argument is the same as for
@scheme[open-input-file].}
@defproc[(file->bytes-lines [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]
[#:line-mode line-mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
bytes?]{
(listof bytes?)]{
Like @scheme[file->lines], but reading bytes and collecting them into
lines like @scheme[read-bytes-line].}

View File

@ -128,6 +128,6 @@
(define-syntax speed
(syntax-rules ()
[(_ id what)
(t "An" (scheme id) "application can provide better performance for"
(t "An " (scheme id) " application can provide better performance for "
(elem what)
"iteration when it appears directly in a" (scheme for) "clause.")])))
" iteration when it appears directly in a " (scheme for) " clause.")])))

View File

@ -849,6 +849,58 @@ Returns @scheme[#t] if the native encoding of numbers is big-endian
for the machine running Scheme, @scheme[#f] if the native encoding
is little-endian.}
@; ------------------------------------------------------------------------
@section{Inexact-Real Vectors}
A @deftech{flvector} is like a @tech{vector}, but it holds only
inexact real numbers. This representation can be more compact, and
unsafe operations on @tech{flvector}s (see
@schememodname[scheme/unsafe/ops]) can execute more efficiently than
unsafe operations on @tech{vectors} of inexact reals.
An f64vector as provided by @schememodname[scheme/foreign] stores the
same kinds of values as an @tech{flvector}, but with extra
indirections that make f64vectors more convenient for working with
foreign libraries. The lack of indirections make unsafe
@tech{flvector} access more efficient.
@defproc[(flvector? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a @tech{flvector}, @scheme[#f] otherwise.}
@defproc[(flvector [x inexact-real?] ...) flvector?]{
Creates a @tech{flvector} containing the given inexact real numbers.}
@defproc[(make-flvector [size exact-nonnegative-integer?]
[x inexact-real? 0.0])
flvector?]{
Creates a @tech{flvector} with @scheme[size] elements, where every
slot in the @tech{flvector} is filled with @scheme[x].}
@defproc[(flvector-length [vec flvector?]) exact-nonnegative-integer?]{
Returns the length of @scheme[vec] (i.e., the number of slots in the
@tech{flvector}).}
@defproc[(flvector-ref [vec flvector?] [pos exact-nonnegative-integer?])
inexact-real?]{
Returns the inexact real number in slot @scheme[pos] of
@scheme[vec]. The first slot is position @scheme[0], and the last slot
is one less than @scheme[(flvector-length vec)].}
@defproc[(flvector-set! [vec flvector?] [pos exact-nonnegative-integer?]
[x inexact-real?])
inexact-real?]{
Sets the inexact real number in slot @scheme[pos] of @scheme[vec]. The
first slot is position @scheme[0], and the last slot is one less than
@scheme[(flvector-length vec)].}
@; ------------------------------------------------------------------------
@section{Extra Constants and Functions}
@ -901,13 +953,15 @@ Returns the hyperbolic tangent of @scheme[z].}
Computes the greatest exact integer @scheme[m] such that:
@schemeblock[(<= (expt 10 m)
(inexact->exact r))]
Hence also
Hence also:
@schemeblock[(< (inexact->exact r)
(expt 10 (add1 m)))].
(expt 10 (add1 m)))]
@mz-examples[#:eval math-eval
(order-of-magnitude 999)
(order-of-magnitude 1000)]
(order-of-magnitude 1000)
(order-of-magnitude 1/100)
(order-of-magnitude 1/101)]
}
@; ----------------------------------------------------------------------

View File

@ -878,12 +878,12 @@ without building the intermediate list.
]}
@defproc[(count [proc procedure?] [lst list?] ...+)
list?]{
exact-nonnegative-integer?]{
Returns @scheme[(length (filter proc lst ...))], but
without building the intermediate list.
Returns @scheme[(length (filter proc lst ...))], but without building
the intermediate list.
@mz-examples[
@mz-examples[#:eval list-eval
(count positive? '(1 -1 2 3 -2 5))
]}

View File

@ -53,8 +53,18 @@ result is @scheme[values].
Returns a procedure that is like @scheme[proc], except that its name
as returned by @scheme[object-name] (and as printed for debugging) is
@scheme[name].}
@scheme[name].
The given @scheme[name] is used for printing an error message if the
resulting procedure is applied to the wrong number of arguments. In
addition, if @scheme[proc] is an @tech{accessor} or @tech{mutator}
produced by @scheme[define-struct],
@scheme[make-struct-field-accessor], or
@scheme[make-struct-field-mutator], the resulting procedure also uses
@scheme[name] when its (first) argument has the wrong type. More
typically, however, @scheme[name] is not used for reporting errors,
since the procedure name is typically hard-wired into an internal
check.}
@; ----------------------------------------
@section{Keywords and Arity}
@ -243,7 +253,7 @@ See also @scheme[procedure-arity?].}
@defthing[prop:procedure struct-type-property?]{
A @tech{structure type property} to indentify structure types whose
A @tech{structure type property} to identify structure types whose
instances can be applied as procedures. In particular, when
@scheme[procedure?] is applied to the instance, the result will be
@scheme[#t], and when an instance is used in the function position of
@ -441,8 +451,8 @@ primitive closure rather than a simple primitive procedure,
Returns the arity of the result of the primitive procedure
@scheme[prim] (as opposed to the procedure's input arity as returned
by @scheme[arity]). For most primitives, this procedure returns
@scheme[1], since most primitives return a single value when
by @scheme[procedure-arity]). For most primitives, this procedure
returns @scheme[1], since most primitives return a single value when
applied.}
@; ----------------------------------------

View File

@ -63,7 +63,7 @@ is identified by the @scheme[prop:set!-transformer] property of
@defthing[prop:set!-transformer struct-type-property?]{
A @tech{structure type property} to indentify structure types that act
A @tech{structure type property} to identify structure types that act
as @tech{assignment transformers} like the ones created by
@scheme[make-set!-transformer].
@ -133,7 +133,7 @@ create @scheme[transformer] or as indicated by a
@defthing[prop:rename-transformer struct-type-property?]{
A @tech{structure type property} to indentify structure types that act
A @tech{structure type property} to identify structure types that act
as @tech{rename transformers} like the ones created by
@scheme[make-rename-transformer].
@ -576,8 +576,9 @@ exports of the module.
Returns @scheme[id-stx] if no binding in the current expansion context
shadows @scheme[id-stx] (ignoring unsealed @tech{internal-definition
contexts}), if @scheme[id-stx] has no module bindings in its lexical
information, and if the current expansion context is not a
contexts} and identifiers that had the @indexed-scheme['unshadowable]
@tech{syntax property}), if @scheme[id-stx] has no module bindings in
its lexical information, and if the current expansion context is not a
@tech{module context}.
If a binding of @scheme[inner-identifier] shadows @scheme[id-stx], the

View File

@ -1,6 +1,10 @@
#lang scribble/doc
@(require "mz.ss"
(for-label scheme/unsafe/ops))
(for-label scheme/unsafe/ops
(only-in scheme/foreign
f64vector?
f64vector-ref
f64vector-set!)))
@title[#:tag "unsafe"]{Unsafe Operations}
@ -165,6 +169,27 @@ Unsafe versions of @scheme[bytes-length], @scheme[bytes-ref], and
fixnum).}
@deftogether[(
@defproc[(unsafe-flvector-length [v flvector?]) fixnum?]
@defproc[(unsafe-flvector-ref [v flvector?][k fixnum?]) any/c]
@defproc[(unsafe-flvector-set! [v flvector?][k fixnum?][x inexact-real?]) void?]
)]{
Unsafe versions of @scheme[flvector-length], @scheme[flvector-ref], and
@scheme[flvector-set!]. A @tech{flvector}'s size can never be larger than a
@tech{fixnum} (so even @scheme[flvector-length] always returns a
fixnum).}
@deftogether[(
@defproc[(unsafe-f64vector-ref [vec f64vector?][k fixnum?]) inexact-real?]
@defproc[(unsafe-f64vector-set! [vec f64vector?][k fixnum?][n inexact-real?]) void?]
)]{
Unsafe versions of @scheme[f64vector-ref] and
@scheme[f64vector-set!].}
@deftogether[(
@defproc[(unsafe-struct-ref [v any/c][k fixnum?]) any/c]
@defproc[(unsafe-struct-set! [v any/c][k fixnum?][val any/c]) void?]

View File

@ -184,7 +184,7 @@ Applies @scheme[proc] to the elements of the @scheme[vec]s from the
v
]}
@defproc[(vector-append [lst list?] ...) list?]{
@defproc[(vector-append [vec vector?] ...) vector?]{
Creates a fresh vector that contains all
of the elements of the given vectors in order.
@ -194,19 +194,19 @@ of the elements of the given vectors in order.
}
@defproc[(vector-take [vec vector?] [pos exact-nonnegative-integer?]) list?]{
@defproc[(vector-take [vec vector?] [pos exact-nonnegative-integer?]) vector?]{
Returns a fresh vector whose elements are the first @scheme[pos] elements of
@scheme[vec]. If @scheme[vec] has fewer than
@scheme[pos] elements, the @exnraise[exn:fail:contract].
@scheme[pos] elements, then the @exnraise[exn:fail:contract].
@mz-examples[#:eval vec-eval
(vector-take #(1 2 3 4) 2)
]}
@defproc[(vector-take-right [vec vector?] [pos exact-nonnegative-integer?]) list?]{
@defproc[(vector-take-right [vec vector?] [pos exact-nonnegative-integer?]) vector?]{
Returns a fresh vector whose elements are the last @scheme[pos] elements of
@scheme[vec]. If @scheme[vec] has fewer than
@scheme[pos] elements, the @exnraise[exn:fail:contract].
@scheme[pos] elements, then the @exnraise[exn:fail:contract].
@mz-examples[#:eval vec-eval
(vector-take-right #(1 2 3 4) 2)
@ -215,7 +215,7 @@ Returns a fresh vector whose elements are the last @scheme[pos] elements of
@defproc[(vector-drop [vec vector?] [pos exact-nonnegative-integer?]) vector?]{
Returns a fresh vector whose elements are the elements of @scheme[vec]
after the first @scheme[pos] elements. If @scheme[vec] has fewer
than @scheme[pos] elements, the @exnraise[exn:fail:contract].
than @scheme[pos] elements, then the @exnraise[exn:fail:contract].
@mz-examples[#:eval vec-eval
(vector-drop #(1 2 3 4) 2)
@ -224,7 +224,7 @@ Returns a fresh vector whose elements are the elements of @scheme[vec]
@defproc[(vector-drop-right [vec vector?] [pos exact-nonnegative-integer?]) vector?]{
Returns a fresh vector whose elements are the elements of @scheme[vec]
before the first @scheme[pos] elements. If @scheme[vec] has fewer
than @scheme[pos] elements, the @exnraise[exn:fail:contract].
than @scheme[pos] elements, then the @exnraise[exn:fail:contract].
@mz-examples[#:eval vec-eval
(vector-drop-right #(1 2 3 4) 2)
@ -288,11 +288,11 @@ returns @scheme[#f].
]}
@defproc[(vector-count [proc procedure?] [lst list?] ...+)
list?]{
@defproc[(vector-count [proc procedure?] [vec vector?] ...+)
exact-nonnegative-integer?]{
Returns @scheme[(vector-length (vector-filter proc lst ...))], but
without building the intermediate list.
Returns the number of elements of the @scheme[vec ...] (taken in
parallel) on which @scheme[proc] does not evaluate to @scheme[#f].
@mz-examples[#:eval vec-eval
(vector-count even? #(1 2 3 4 5))

View File

@ -574,6 +574,11 @@ Shows the interactions window
Returns the currently active tab.
}
@defmethod[(open-in-new-tab [filename (or/c path-string? #f)]) void?]{
Opens a new tab in this frame. If @scheme[filename] is a @scheme[path-string?],
It loads that file in the definitions window of the new tab.
}
@defmethod[#:mode public-final (close-current-tab) void?]{
Closes the current tab, making some other tab visible.

View File

@ -390,13 +390,13 @@
(define (time>=? time1 time2)
(tm:time-compare-check time1 time2 'time>=?)
(or (>= (time-second time1) (time-second time2))
(or (> (time-second time1) (time-second time2))
(and (= (time-second time1) (time-second time2))
(>= (time-nanosecond time1) (time-nanosecond time2)))))
(define (time<=? time1 time2)
(tm:time-compare-check time1 time2 'time<=?)
(or (<= (time-second time1) (time-second time2))
(or (< (time-second time1) (time-second time2))
(and (= (time-second time1) (time-second time2))
(<= (time-nanosecond time1) (time-nanosecond time2)))))

View File

@ -21,41 +21,42 @@
(if (not (and (pair? body)
(pair? (cdr body))
(keyword? (syntax-e (car body)))))
(datum->syntax stx body stx)
(let* ([k (car body)] [k* (syntax-e k)] [v (cadr body)])
(case k*
[(kwd) (if var
(err (format "got two ~s keywords" k*) k)
(begin (set! var v) (loop (cddr body))))]
...
[else (err "got an unknown keyword" (car body))])))))
(datum->syntax stx body stx)
(let* ([k (car body)] [k* (syntax-e k)] [v (cadr body)])
(case k*
[(kwd) (if var
(err (format "got two ~s keywords" k*) k)
(begin (set! var v) (loop (cddr body))))]
...
[else (err "got an unknown keyword" (car body))])))))
checks ...
(unless var (set! var default)) ...))
(define <lang-id> (datum->syntax stx 'language-module stx))
(define <data-id> (datum->syntax stx 'language-data stx))
(define (construct-reader lang body)
(keywords body
[#:language ~lang lang]
[#:read ~read #'read]
[#:read-syntax ~read-syntax #'read-syntax]
[#:wrapper1 ~wrapper1 #'#f]
[#:wrapper2 ~wrapper2 #'#f]
[#:whole-body-readers? ~whole-body-readers? #'#f]
[#:info ~info #'#f]
[(when (equal? (and lang #t) (and ~lang #t))
(err (string-append
"must specify either a module language, or #:language"
(if (and lang ~lang) ", not both" ""))))
(unless (equal? (and ~read #t) (and ~read-syntax #t))
(err "must specify either both #:read and #:read-syntax, or none"))
(when (and ~whole-body-readers? (not (and ~read ~read-syntax)))
(err "got a #:whole-body-readers? without #:read and #:read-syntax"))])
;; FIXME: a lot of the generated code is constant and should be lifted
;; out of the template:
[#:language ~lang lang]
[#:read ~read #'read]
[#:read-syntax ~read-syntax #'read-syntax]
[#:wrapper1 ~wrapper1 #'#f]
[#:wrapper2 ~wrapper2 #'#f]
[#:whole-body-readers? ~whole-body-readers? #'#f]
[#:info ~info #'#f]
[(when (equal? (and lang #t) (and ~lang #t))
(err (string-append
"must specify either a module language, or #:language"
(if (and lang ~lang) ", not both" ""))))
(unless (equal? (and ~read #t) (and ~read-syntax #t))
(err "must specify either both #:read and #:read-syntax, or none"))
(when (and ~whole-body-readers? (not (and ~read ~read-syntax)))
(err "got a #:whole-body-readers? without #:read and #:read-syntax"))])
;; FIXME: some generated code is constant and should be lifted out of the
;; template:
(quasisyntax/loc stx
(#%module-begin
#,@body
(#%provide (rename lang:read read) (rename lang:read-syntax read-syntax)
(#%provide (rename lang:read read)
(rename lang:read-syntax read-syntax)
read-properties get-info-getter get-info)
(define (lang:read in modpath line col pos)
(wrap-internal/wrapper #f #f in modpath line col pos))
@ -66,49 +67,27 @@
[lang (car props)] [#,<lang-id> lang] ;\ visible in
[data (cadr props)] [#,<data-id> data] ;/ user-code
[read (if stx?
(let ([rd #,~read-syntax]) (lambda (in) (rd src in)))
#,~read)]
(let ([rd #,~read-syntax])
(lambda (in) (rd src in)))
#,~read)]
[w1 #,~wrapper1]
[w2 #,~wrapper2]
[whole? #,~whole-body-readers?]
[rd (lambda (in) (wrap-internal (if (and (not stx?) (syntax? lang))
(syntax->datum lang)
lang)
in read whole? w1 stx?
modpath src line col pos))]
[rd (lambda (in)
(wrap-internal (if (and (not stx?) (syntax? lang))
(syntax->datum lang)
lang)
in read whole? w1 stx?
modpath src line col pos))]
[r (cond [(not w2) (rd in)]
[(ar? w2 3) (w2 in rd stx?)]
[else (w2 in rd)])])
(if stx?
(syntax-property r 'module-language
(vector (syntax->datum modpath) 'get-info-getter
props))
r)))
(define lang*
(let ([lang #,~lang])
(if (not (procedure? lang))
(list lang #f)
(cond [(ar? lang 5) lang]
[(ar? lang 1) (lambda (in . _) (lang in))]
[(ar? lang 0) (lambda _ (lang))]
[else (raise-type-error
'syntax/module-reader
"language+reader procedure of 5, 1, or 0 arguments"
lang)]))))
(define (read-properties in modpath line col pos)
(if (not (procedure? lang*))
lang*
(call-with-values
(lambda () (parameterize ([current-input-port in])
(lang* in modpath line col pos)))
(lambda xs
(case (length xs)
[(2) xs] [(1) (list (car xs) #f)]
[else (error 'syntax/module-reader
"wrong number of results from ~a, ~a ~e"
"the #:language function"
"expected 1 or 2 values, got"
(length xs))])))))
(syntax-property r
'module-language
(vector (syntax->datum modpath) 'get-info-getter props))
r)))
(define read-properties (lang->read-properties #,~lang))
(define (get-info in modpath line col pos)
(get-info-getter (read-properties in modpath line col pos)))
(define (get-info-getter props)
@ -124,14 +103,14 @@
[#,<data-id> data] ;/ user-code
[info #,~info])
(if (or (not info) (and (procedure? info) (ar? info 3)))
info
(raise-type-error 'syntax/module-reader
"info procedure of 3 arguments" info))))
info
(raise-type-error 'syntax/module-reader
"info procedure of 3 arguments" info))))
(define (language-info what defval)
(if info
(let ([r (info what defval default-info)])
(if (eq? r default-info) (default-info what defval) r))
(default-info what defval)))
(let ([r (info what defval default-info)])
(if (eq? r default-info) (default-info what defval) r))
(default-info what defval)))
language-info))))
(syntax-case stx ()
[(_ lang body ...)
@ -139,55 +118,104 @@
(construct-reader #''lang (syntax->list #'(body ...)))]
[(_ body ...) (construct-reader #f (syntax->list #'(body ...)))]))
;; turns the language specification (either a language or some flavor of a
;; function that returns a language and some properties) into a function that
;; returns (list <lang> <props>)
(define (lang->read-properties lang)
(define lang*
(cond [(not (procedure? lang)) (list lang #f)]
[(ar? lang 5) lang]
[(ar? lang 1) (lambda (in . _) (lang in))]
[(ar? lang 0) (lambda _ (lang))]
[else (raise-type-error
'syntax/module-reader
"language+reader procedure of 5, 1, or 0 arguments"
lang)]))
(define (read-properties in modpath line col pos)
(if (not (procedure? lang*))
lang*
(parameterize ([current-input-port in])
(call-with-values
(lambda () (lang* in modpath line col pos))
(lambda xs
(case (length xs)
[(2) xs] [(1) (list (car xs) #f)]
[else (error 'syntax/module-reader
"wrong number of results from ~a, ~a ~e"
"the #:language function"
"expected 1 or 2 values, got"
(length xs))]))))))
read-properties)
;; Since there are users that wrap with `#%module-begin' in their reader
;; or wrapper1 functions, we need to avoid double-wrapping. Having to do
;; this for #lang readers should be considered deprecated, and hopefully
;; one day we'll move to just doing it unilaterally (making this code throw
;; an error in that case before that's done).
;; This function takes "body" as a sequence of expressions (can be syntaxes
;; and/or sexprs) and returns a new body as a *single* expression that is
;; wrapped in a `#%module-begin' -- using the input if it was a single
;; pre-wrapped expression.
(define (wrap-module-begin body)
(let ([exprs (if (syntax? body) (syntax->list body) body)])
(if (and (pair? exprs) (null? (cdr exprs))
(let* ([x (car exprs)]
[x (if (syntax? x) (syntax-e x) x)]
[x (and (pair? x) (car x))]
[x (if (syntax? x) (syntax-e x) x)])
(eq? x '#%module-begin)))
(car exprs)
(cons '#%module-begin body))))
(define (wrap-internal lang port read whole? wrapper stx?
modpath src line col pos)
(let* ([lang (if stx? (datum->syntax #f lang modpath modpath) lang)]
[body (lambda ()
(if whole?
(read port)
(let loop ([a null])
(let ([v (read port)])
(if (eof-object? v) (reverse a) (loop (cons v a)))))))]
(read port)
(let loop ([a null])
(let ([v (read port)])
(if (eof-object? v)
(reverse a)
(loop (cons v a)))))))]
[body (cond [(not wrapper) (body)]
[(ar? wrapper 2) (wrapper body stx?)]
[else (wrapper body)])]
[body (wrap-module-begin body)]
[all-loc (vector src line col pos
(let-values ([(l c p) (port-next-location port)])
(and p (- p pos))))]
[body (if (and stx? (not (syntax? body)))
(datum->syntax #f body all-loc)
body)]
[p-name (object-name port)]
[name (if (path? p-name)
(let-values ([(base name dir?) (split-path p-name)])
(string->symbol
(path->string (path-replace-suffix name #""))))
'page)]
(let-values ([(base name dir?) (split-path p-name)])
(string->symbol
(path->string (path-replace-suffix name #""))))
'anonymous-module)]
[tag-src (lambda (v)
(if stx?
(datum->syntax
#f v (vector src line col pos
(- (or (syntax-position modpath) (add1 pos))
pos)))
v))]
[r `(,(tag-src 'module) ,(tag-src name) ,lang . ,body)])
(datum->syntax
#f v (vector src line col pos
(- (or (syntax-position modpath)
(add1 pos))
pos)))
v))]
[r `(,(tag-src 'module) ,(tag-src name) ,lang ,body)])
(if stx? (datum->syntax #f r all-loc) r)))
(define (wrap lang port read modpath src line col pos)
(wrap-internal lang port read #f #f #f modpath src line col pos))
(define (make-meta-reader self-sym module-path-desc spec->module-path
convert-read
convert-read-syntax
convert-get-info
#:read-spec [read-spec
(lambda (in)
(let ([spec (regexp-try-match #px"^[ \t]+(.*?)(?=\\s|$)" in)])
(and spec
(let ([s (cadr spec)])
(if (equal? s "")
#f
s)))))])
(define (make-meta-reader
self-sym module-path-desc spec->module-path
convert-read
convert-read-syntax
convert-get-info
#:read-spec
[read-spec
(lambda (in)
(let ([spec (regexp-try-match #px"^[ \t]+(.*?)(?=\\s|$)" in)])
(and spec (let ([s (cadr spec)])
(if (equal? s "") #f s)))))])
(define (get in export-sym src line col pos mk-fail-thunk)
(define (bad str eof?)
((if eof? raise-read-eof-error raise-read-error)
@ -198,35 +226,41 @@
(and pos pos2 (- pos2 pos)))))
(define spec (read-spec in))
(if (not spec)
(bad #f (eof-object? (peek-byte in)))
(let ([parsed-spec (spec->module-path spec)])
(if parsed-spec
(begin ((current-reader-guard) parsed-spec)
(dynamic-require parsed-spec export-sym (mk-fail-thunk spec)))
(bad spec #f)))))
(bad #f (eof-object? (peek-byte in)))
(let ([parsed-spec (spec->module-path spec)])
(if parsed-spec
(begin ((current-reader-guard) parsed-spec)
(dynamic-require parsed-spec export-sym
(mk-fail-thunk spec)))
(bad spec #f)))))
(define (-get-info inp mod line col pos)
(let ([r (get inp 'get-info (object-name inp) line col pos
(lambda (spec) (lambda () (lambda (inp mod line col pos)
(lambda (tag defval) defval)))))])
(lambda (spec)
(lambda ()
(lambda (inp mod line col pos)
(lambda (tag defval) defval)))))])
(convert-get-info (r inp mod line col pos))))
(define (read-fn in read-sym args src mod line col pos convert)
(let ([r (get in read-sym src #|mod|# line col pos
(lambda (spec)
(lambda ()
(error self-sym "cannot find reader for `#lang ~a ~a'"
(error read-sym "cannot find reader for `#lang ~a ~a'"
self-sym
spec))))])
(let ([r (convert r)])
(if (and (procedure? r) (procedure-arity-includes? r (+ 5 (length args))))
(apply r (append args (list in mod line col pos)))
(apply r (append args (list in)))))))
(if (and (procedure? r)
(procedure-arity-includes? r (+ 5 (length args))))
(apply r (append args (list in mod line col pos)))
(apply r (append args (list in)))))))
(define (-read inp mod line col pos)
(read-fn inp 'read null (object-name inp) mod line col pos convert-read))
(read-fn inp 'read null (object-name inp) mod line col pos
convert-read))
(define (-read-syntax src inp mod line col pos)
(read-fn inp 'read-syntax (list src) src mod line col pos convert-read-syntax))
(read-fn inp 'read-syntax (list src) src mod line col pos
convert-read-syntax))
(values -read -read-syntax -get-info)))

View File

@ -4,6 +4,7 @@
scheme/dict)
(provide id-table-position?)
#|
(require (rename-in scheme/base [car s:car]))
(define-syntax (car stx)
(syntax-case stx ()
@ -13,7 +14,7 @@
'#,(syntax-line stx)
'#,(syntax-column stx))))
(s:car x))]))
|#
(define-struct id-table-position (a b))

View File

@ -1,7 +1,7 @@
#lang scheme/base
(require unstable/struct
(for-syntax scheme/base unstable/struct))
(provide match)
(for-syntax scheme/base scheme/struct-info unstable/struct))
(provide match make)
(define-syntax (match stx)
(syntax-case stx ()
@ -25,7 +25,7 @@
;; (match-p id Pattern SuccessExpr FailureExpr)
(define-syntax (match-p stx)
(syntax-case stx (quote cons list)
(syntax-case stx (quote cons list make struct)
[(match-p x wildcard success failure)
(and (identifier? #'wildcard) (free-identifier=? #'wildcard #'_))
#'success]
@ -46,6 +46,27 @@
[(match-p x var success failure)
(identifier? #'var)
#'(let ([var x]) success)]
[(match-p x (make S p ...) success failure)
#'(match-p x (struct S (p ...)) success failure)]
[(match-p x (struct S (p ...)) success failure)
(identifier? #'S)
(let ()
(define (not-a-struct)
(raise-syntax-error #f "expected struct name" #'S))
(define si (syntax-local-value #'S not-a-struct))
(unless (struct-info? si)
(not-a-struct))
(let* ([si (extract-struct-info si)]
[predicate (list-ref si 2)]
[accessors (reverse (list-ref si 3))])
(unless (andmap identifier? accessors)
(raise-syntax-error #f "struct has incomplete information" #'S))
(with-syntax ([predicate predicate]
[(accessor ...) accessors])
#'(if (predicate x)
(let ([y (list (accessor x) ...)])
(match-p y (list p ...) success failure))
failure))))]
[(match-p x s success failure)
(prefab-struct-key (syntax-e #'s))
(with-syntax ([key (prefab-struct-key (syntax-e #'s))]
@ -55,3 +76,7 @@
(let ([xps (cdr (vector->list (struct->vector x)))])
(match-p xps (list p ...) success failure))
failure)))]))
(define-syntax struct
(lambda (stx)
(raise-syntax-error #f "illegal use of keyword" stx)))

View File

@ -693,13 +693,13 @@
(define (check-list-pattern pattern stx)
(match pattern
[#s(pat:datum _base '())
[(make pat:datum _base '())
#t]
[#s(pat:head _base _head tail)
[(make pat:head _base _head tail)
(check-list-pattern tail stx)]
[#s(pat:dots _base _head tail)
[(make pat:dots _base _head tail)
(check-list-pattern tail stx)]
[#s(pat:compound _base '#:pair (list _head tail))
[(make pat:compound _base '#:pair (list _head tail))
(check-list-pattern tail stx)]
[_
(wrong-syntax stx "expected proper list pattern")]))

View File

@ -18,7 +18,7 @@
(define (default-failure-handler stx0 f)
(match (simplify-failure f)
[#s(failure x frontier expectation)
[(make failure x frontier expectation)
(report-failure stx0 x (dfc->index frontier) (dfc->stx frontier) expectation)]))
(define current-failure-handler
@ -68,14 +68,14 @@
;; simplify* : Failure -> SimpleFailure
(define (simplify* f)
(match f
[#s(join-failures f1 f2)
[(make join-failures f1 f2)
(choose-error (simplify* f1) (simplify* f2))]
[#s(failure x frontier expectation)
[(make failure x frontier expectation)
(match expectation
[#s(expect:thing description '#t chained)
[(make expect:thing description '#t chained)
(let ([chained* (simplify* chained)])
(match chained*
[#s(failure _ chained*-frontier chained*-expectation)
[(make failure _ chained*-frontier chained*-expectation)
(cond [(ineffable? chained*-expectation)
;; If simplified chained failure is ineffable,
;; keep (& adjust) its frontier
@ -93,14 +93,14 @@
;; FIXME: try different selection/simplification algorithms/heuristics
(define (simplify-failure0 f)
(match f
[#s(join-failures f1 f2)
[(make join-failures f1 f2)
(choose-error (simplify-failure0 f1) (simplify-failure0 f2))]
[#s(failure x frontier expectation)
[(make failure x frontier expectation)
(match expectation
[#s(expect:thing description '#t chained)
[(make expect:thing description '#t chained)
(let ([chained* (simplify-failure0 chained)])
(match chained*
[#s(failure _ _ chained*-expectation)
[(make failure _ _ chained*-expectation)
(cond [(ineffable? chained*-expectation)
;; If simplified chained failure is ineffable, ignore it
;; and stick to the one with the description
@ -113,7 +113,7 @@
(define (adjust-failure f base-frontier)
(match f
[#s(failure x frontier expectation)
[(make failure x frontier expectation)
(let ([frontier (dfc-append base-frontier frontier)])
(make-failure x frontier expectation))]))
@ -147,15 +147,15 @@
(define (for-alternative e index stx)
(match e
[#s(expect:thing description transparent? chained)
[(make expect:thing description transparent? chained)
(format "expected ~a" description)]
[#s(expect:atom atom)
[(make expect:atom atom)
(format "expected the literal ~s" atom)]
[#s(expect:literal literal)
[(make expect:literal literal)
(format "expected the literal identifier ~s" (syntax-e literal))]
[#s(expect:message message)
[(make expect:message message)
(format "~a" message)]
[#s(expect:pair)
[(make expect:pair)
(cond [(= index 0)
"expected sequence of terms"]
[else

View File

@ -2,6 +2,7 @@
(require scheme/contract/base
scheme/stxparam
scheme/list
unstable/struct
"minimatch.ss"
(for-syntax scheme/base
syntax/stx
@ -159,18 +160,18 @@ A Dynamic Frontier Context (DFC) is one of
(define-struct dfc:pre (parent stx) #:prefab)
(define-struct dfc:post (parent stx) #:prefab)
(define (dfc-empty x) (make-dfc:empty x))
(define (dfc-empty x) (make dfc:empty x))
(define (dfc-add-car parent stx)
(make-dfc:car parent stx))
(make dfc:car parent stx))
(define (dfc-add-cdr parent _)
(match parent
[#s(dfc:cdr uberparent n)
(make-dfc:cdr uberparent (add1 n))]
[_ (make-dfc:cdr parent 1)]))
[(make dfc:cdr uberparent n)
(make dfc:cdr uberparent (add1 n))]
[_ (make dfc:cdr parent 1)]))
(define (dfc-add-pre parent stx)
(make-dfc:pre parent stx))
(make dfc:pre parent stx))
(define (dfc-add-post parent stx)
(make-dfc:post parent stx))
(make dfc:post parent stx))
(define (dfc-add-unbox parent stx)
(dfc-add-car parent stx))
@ -181,16 +182,16 @@ A Dynamic Frontier Context (DFC) is one of
(define (dfc->index dfc)
(match dfc
[#s(dfc:cdr parent n) n]
[(make dfc:cdr parent n) n]
[_ 0]))
(define (dfc->stx dfc)
(match dfc
[#s(dfc:empty stx) stx]
[#s(dfc:car parent stx) stx]
[#s(dfc:cdr parent n) (dfc->stx parent)]
[#s(dfc:pre parent stx) stx]
[#s(dfc:post parent stx) stx]))
[(make dfc:empty stx) stx]
[(make dfc:car parent stx) stx]
[(make dfc:cdr parent n) (dfc->stx parent)]
[(make dfc:pre parent stx) stx]
[(make dfc:post parent stx) stx]))
;; dfc-difference : DFC DFC -> nat
;; Returns N s.t. B = (dfc-add-cdr^N A)
@ -199,10 +200,10 @@ A Dynamic Frontier Context (DFC) is one of
(error 'dfc-difference "~e is not an extension of ~e"
(frontier->sexpr b) (frontier->sexpr a)))
(match (list a b)
[(list #s(dfc:cdr pa na) #s(dfc:cdr pb nb))
[(list (make dfc:cdr pa na) (make dfc:cdr pb nb))
(unless (equal? pa pb) (whoops))
(- nb na)]
[(list pa #s(dfc:cdr pb nb))
[(list pa (make dfc:cdr pb nb))
(unless (equal? pa pb) (whoops))
nb]
[_
@ -213,16 +214,16 @@ A Dynamic Frontier Context (DFC) is one of
;; puts A at the base, B on top
(define (dfc-append a b)
(match b
[#s(dfc:empty stx) a]
[#s(dfc:car pb stx) (make-dfc:car (dfc-append a pb) stx)]
[#s(dfc:cdr #s(dfc:empty _) nb)
[(make dfc:empty stx) a]
[(make dfc:car pb stx) (make dfc:car (dfc-append a pb) stx)]
[(make dfc:cdr (make dfc:empty _) nb)
;; Special case to merge "consecutive" cdr frames
(match a
[#s(dfc:cdr pa na) (make-dfc:cdr pa (+ na nb))]
[_ (make-dfc:cdr a nb)])]
[#s(dfc:cdr pb nb) (make-dfc:cdr (dfc-append a pb) nb)]
[#s(dfc:pre pb stx) (make-dfc:pre (dfc-append a pb) stx)]
[#s(dfc:post pb stx) (make-dfc:post (dfc-append a pb) stx)]))
[(make dfc:cdr pa na) (make dfc:cdr pa (+ na nb))]
[_ (make dfc:cdr a nb)])]
[(make dfc:cdr pb nb) (make dfc:cdr (dfc-append a pb) nb)]
[(make dfc:pre pb stx) (make dfc:pre (dfc-append a pb) stx)]
[(make dfc:post pb stx) (make dfc:post (dfc-append a pb) stx)]))
;; An Inverted DFC (IDFC) is a DFC inverted for easy comparison.
@ -230,15 +231,15 @@ A Dynamic Frontier Context (DFC) is one of
(define (invert-dfc dfc)
(define (invert dfc acc)
(match dfc
[#s(dfc:empty _) acc]
[#s(dfc:car parent stx)
(invert parent (make-dfc:car acc stx))]
[#s(dfc:cdr parent n)
(invert parent (make-dfc:cdr acc n))]
[#s(dfc:pre parent stx)
(invert parent (make-dfc:pre acc stx))]
[#s(dfc:post parent stx)
(invert parent (make-dfc:post acc stx))]))
[(make dfc:empty _) acc]
[(make dfc:car parent stx)
(invert parent (make dfc:car acc stx))]
[(make dfc:cdr parent n)
(invert parent (make dfc:cdr acc n))]
[(make dfc:pre parent stx)
(invert parent (make dfc:pre acc stx))]
[(make dfc:post parent stx)
(invert parent (make dfc:post acc stx))]))
(invert dfc (dfc-empty 'dummy)))
;; compare-idfcs : IDFC IDFC -> (one-of '< '= '>)
@ -247,28 +248,28 @@ A Dynamic Frontier Context (DFC) is one of
(define (compare-idfcs a b)
(match (list a b)
;; Same constructors
[(list #s(dfc:empty _) #s(dfc:empty _)) '=]
[(list #s(dfc:car pa _) #s(dfc:car pb _))
[(list (make dfc:empty _) (make dfc:empty _)) '=]
[(list (make dfc:car pa _) (make dfc:car pb _))
(compare-idfcs pa pb)]
[(list #s(dfc:cdr pa na) #s(dfc:cdr pb nb))
[(list (make dfc:cdr pa na) (make dfc:cdr pb nb))
(cond [(< na nb) '<]
[(> na nb) '>]
[(= na nb) (compare-idfcs pa pb)])]
[(list #s(dfc:pre pa _) #s(dfc:pre pb _))
[(list (make dfc:pre pa _) (make dfc:pre pb _))
;; FIXME: possibly just '= here, treat all sides as equiv
(compare-idfcs pa pb)]
[(list #s(dfc:post pa _) #s(dfc:post pb _))
[(list (make dfc:post pa _) (make dfc:post pb _))
;; FIXME: possibly just '= here, treat all sides as equiv
(compare-idfcs pa pb)]
;; Different constructors
[(list #s(dfc:empty _) _) '<]
[(list _ #s(dfc:empty _)) '>]
[(list #s(dfc:pre _ _) _) '<]
[(list _ #s(dfc:pre _ _)) '>]
[(list #s(dfc:car _ _) _) '<]
[(list _ #s(dfc:car _ _)) '>]
[(list #s(dfc:cdr _ _) _) '<]
[(list _ #s(dfc:cdr _ _)) '>]))
[(list (make dfc:empty _) _) '<]
[(list _ (make dfc:empty _)) '>]
[(list (make dfc:pre _ _) _) '<]
[(list _ (make dfc:pre _ _)) '>]
[(list (make dfc:car _ _) _) '<]
[(list _ (make dfc:car _ _)) '>]
[(list (make dfc:cdr _ _) _) '<]
[(list _ (make dfc:cdr _ _)) '>]))
(define (idfc>? a b)
(eq? (compare-idfcs a b) '>))
@ -344,7 +345,7 @@ A Dynamic Frontier Context (DFC) is one of
(lambda (f1)
(let ([combining-fail
(lambda (f2)
(fail (make-join-failures f1 f2)))])
(fail (make join-failures f1 f2)))])
(try* rest-attempts combining-fail)))])
(first-attempt next-fail)))))
@ -380,7 +381,7 @@ An Expectation is one of
(or/c expect? (symbols 'ineffable)))
(define (merge-expectations a b)
(make-expect:disj a b))
(make expect:disj a b))
;; expect->alternatives : Expectation -> (listof Expectation)/#f
;; #f indicates 'ineffable somewhere in expectation
@ -541,7 +542,7 @@ An Expectation is one of
(define fs
(let loop ([f f])
(match f
[#s(join-failures f1 f2)
[(make join-failures f1 f2)
(append (loop f1) (loop f2))]
[_ (list f)])))
(case (length fs)
@ -550,20 +551,21 @@ An Expectation is one of
(define (one-failure->sexpr f)
(match f
[#s(failure x frontier expectation)
[(make failure x frontier expectation)
`(failure ,(frontier->sexpr frontier)
#:term ,(syntax->datum x)
#:expected ,(expectation->sexpr expectation))]))
(define (frontier->sexpr dfc)
(match (invert-dfc dfc)
[#s(dfc:empty _) '()]
[#s(dfc:car p _) (cons 0 (frontier->sexpr p))]
[#s(dfc:cdr p n) (cons n (frontier->sexpr p))]
[#s(dfc:side p _) (cons 'side (frontier->sexpr p))]))
[(make dfc:empty _) '()]
[(make dfc:car p _) (cons 0 (frontier->sexpr p))]
[(make dfc:cdr p n) (cons n (frontier->sexpr p))]
[(make dfc:pre p _) (cons 'pre (frontier->sexpr p))]
[(make dfc:post p _) (cons 'post (frontier->sexpr p))]))
(define (expectation->sexpr expectation)
(match expectation
[#s(expect:thing thing '#t chained)
(make-expect:thing thing #t (failure->sexpr chained))]
[(make expect:thing thing '#t chained)
(make expect:thing thing #t (failure->sexpr chained))]
[_ expectation]))

View File

@ -2,7 +2,8 @@
@(require "common.ss")
@(require (for-label syntax/module-reader
(only-in scribble/reader read-syntax-inside read-inside)))
(only-in scribble/reader
read-syntax-inside read-inside)))
@title[#:tag "module-reader"]{Module Reader}
@ -15,16 +16,17 @@ is the name of the module that will be used in the language position
of read modules; using keywords, the resulting readers can be
customized in a number of ways.
@defform*/subs[[(#%module-begin module-path)
(#%module-begin module-path reader-option ... body ....)
(#%module-begin reader-option ... body ....)]
([reader-option (code:line #:language lang-expr)
(code:line #:read read-expr)
(code:line #:read-syntax read-syntax-expr)
(code:line #:info info-expr)
(code:line #:wrapper1 wrapper1-expr)
(code:line #:wrapper2 wrapper2-expr)
(code:line #:whole-body-readers? whole?-expr)])]{
@defform*/subs[
[(#%module-begin module-path)
(#%module-begin module-path reader-option ... body ....)
(#%module-begin reader-option ... body ....)]
([reader-option (code:line #:language lang-expr)
(code:line #:read read-expr)
(code:line #:read-syntax read-syntax-expr)
(code:line #:info info-expr)
(code:line #:wrapper1 wrapper1-expr)
(code:line #:wrapper2 wrapper2-expr)
(code:line #:whole-body-readers? whole?-expr)])]{
Causes a module written in the @schememodname[syntax/module-reader]
language to define and provide @schemeidfont{read} and
@ -37,26 +39,25 @@ That is, a module @scheme[_something]@scheme[/lang/reader] implemented
as
@schemeblock[
(module reader syntax/module-reader
module-path)
(module reader syntax/module-reader
module-path)
]
creates a reader that converts @scheme[#,(hash-lang)_something]
into
creates a reader that converts @scheme[#,(hash-lang)_something] into
@schemeblock[
(module _name-id module-path
....)
(module _name-id module-path
(#%module-begin ....))
]
where @scheme[_name-id] is derived from the name of the port used by
the reader.
the reader, or @scheme[anonymous-module] if the port has no name.
For example, @scheme[scheme/base/lang/reader] is implemented as
@schemeblock[
(module reader syntax/module-reader
scheme/base)
(module reader syntax/module-reader
scheme/base)
]
The reader functions can be customized in a number of ways, using
@ -68,10 +69,10 @@ reading. For example, you can implement a
using:
@schemeblock[
(module reader syntax/module-reader
honu
#:read read-honu
#:read-syntax read-honu-syntax)
(module reader syntax/module-reader
honu
#:read read-honu
#:read-syntax read-honu-syntax)
]
Similarly, the @scheme[#:info] keyword supplies a procedure to be used
@ -82,17 +83,17 @@ procedure (to be called with the key and default result for default
handling). If @scheme[#:info] is not supplied, the default
info-getting procedure is used.
You can also use the (optional) module @scheme[body] forms to provide more
definitions that might be needed to implement your reader functions.
For example, here is a case-insensitive reader for the
You can also use the (optional) module @scheme[body] forms to provide
more definitions that might be needed to implement your reader
functions. For example, here is a case-insensitive reader for the
@scheme[scheme/base] language:
@schemeblock[
(module reader syntax/module-reader
scheme/base
#:read (wrap read) #:read-syntax (wrap read-syntax)
(define ((wrap reader) . args)
(parameterize ([read-case-sensitive #f]) (apply reader args))))
(module reader syntax/module-reader
scheme/base
#:read (wrap read) #:read-syntax (wrap read-syntax)
(define ((wrap reader) . args)
(parameterize ([read-case-sensitive #f]) (apply reader args))))
]
In many cases, however, the standard @scheme[read] and
@ -105,11 +106,11 @@ alternative definition of the case-insensitive language using
@scheme[#:wrapper1]:
@schemeblock[
(module reader syntax/module-reader
scheme/base
#:wrapper1 (lambda (t)
(parameterize ([read-case-sensitive #f])
(t))))
(module reader syntax/module-reader
scheme/base
#:wrapper1 (lambda (t)
(parameterize ([read-case-sensitive #f])
(t))))
]
Note that using a @tech[#:doc refman]{readtable}, you can implement
@ -125,11 +126,11 @@ that corresponds to a file). Here is the case-insensitive implemented
using this option:
@schemeblock[
(module reader syntax/module-reader
scheme/base
#:wrapper2 (lambda (in r)
(parameterize ([read-case-sensitive #f])
(r in))))
(module reader syntax/module-reader
scheme/base
#:wrapper2 (lambda (in r)
(parameterize ([read-case-sensitive #f])
(r in))))
]
In some cases, the reader functions read the whole file, so there is
@ -148,10 +149,9 @@ the resulting readers:
following reader defines a ``language'' that ignores the contents
of the file, and simply reads files as if they were empty:
@schemeblock[
(module ignored syntax/module-reader
scheme/base
#:wrapper1 (lambda (t) (t) '()))
]
(module ignored syntax/module-reader
scheme/base
#:wrapper1 (lambda (t) (t) '()))]
Note that it is still performing the read, otherwise the module
loader will complain about extra expressions.}
@item{The reader function that is passed to a @scheme[#:wrapper2]
@ -168,22 +168,22 @@ scribble syntax, and the first datum in the file determines the actual
language (which means that the library specification is effectively
ignored):
@schemeblock[
(module reader syntax/module-reader
-ignored-
#:wrapper2
(lambda (in rd stx?)
(let* ([lang (read in)]
[mod (parameterize ([current-readtable
(make-at-readtable)])
(rd in))]
[mod (if stx? mod (datum->syntax #f mod))]
[r (syntax-case mod ()
[(module name lang* . body)
(with-syntax ([lang (datum->syntax
#'lang* lang #'lang*)])
(syntax/loc mod (module name lang . body)))])])
(if stx? r (syntax->datum r))))
(require scribble/reader))
(module reader syntax/module-reader
-ignored-
#:wrapper2
(lambda (in rd stx?)
(let* ([lang (read in)]
[mod (parameterize ([current-readtable
(make-at-readtable)])
(rd in))]
[mod (if stx? mod (datum->syntax #f mod))]
[r (syntax-case mod ()
[(module name lang* . body)
(with-syntax ([lang (datum->syntax
#'lang* lang #'lang*)])
(syntax/loc mod (module name lang . body)))])])
(if stx? r (syntax->datum r))))
(require scribble/reader))
]
This ability to change the language position in the resulting module
@ -191,22 +191,33 @@ expression can be useful in cases such as the above, where the base
language module is chosen based on the input. To make this more
convenient, you can omit the @scheme[module-path] and instead specify
it via a @scheme[#:language] expression. This expression can evaluate
to a datum or syntax object that is used as a language, or it can evaluate to a thunk.
In the latter case, the thunk is invoked to obtain such a datum
before reading the module body begins, in a dynamic extent where
@scheme[current-input-port] is the source input. A syntax object is converted
using @scheme[syntax->datum] when a datum is needed (for @scheme[read] instead of @scheme[read-syntax]).
Using @scheme[#:language], the last
example above can be written more concisely:
to a datum or syntax object that is used as a language, or it can
evaluate to a thunk. In the latter case, the thunk is invoked to
obtain such a datum before reading the module body begins, in a
dynamic extent where @scheme[current-input-port] is the source
input. A syntax object is converted using @scheme[syntax->datum] when
a datum is needed (for @scheme[read] instead of @scheme[read-syntax]).
Using @scheme[#:language], the last example above can be written more
concisely:
@schemeblock[
(module reader syntax/module-reader
#:language read
#:wrapper2 (lambda (in rd stx?)
(parameterize ([current-readtable
(make-at-readtable)])
(rd in)))
(require scribble/reader))
(module reader syntax/module-reader
#:language read
#:wrapper2 (lambda (in rd stx?)
(parameterize ([current-readtable
(make-at-readtable)])
(rd in)))
(require scribble/reader))
]
Note: if such whole-body reader functions return a list with a single
expression that begins with @scheme[#%module-begin], then the
@scheme[syntax/module-reader] language will not inappropriately add
another. This for backwards-compatibility with older code: having a
whole-body reader functions or wrapper functions that return a
@scheme[#%module-begin]-wrapped body is deprectaed.
}
@ -227,7 +238,8 @@ procedures chains to another language that is specified in an input
stream.
@margin-note{The @schememodname[at-exp], @schememodname[reader], and
@schememodname[planet] languages are implemented using this function.}
@schememodname[planet] languages are implemented using this
function.}
The generated functions expect a target language description in the
input stream that is provided to @scheme[read-spec]. The default
@ -239,8 +251,9 @@ reader exception is raised, and @scheme[path-desc-str] is used as a
description of the expected language form in the error message.
@margin-note{The @schememodname[reader] language supplies
@scheme[read] for @scheme[read-spec]. The @schememodname[at-exp] and
@schememodname[planet] languages use the default @scheme[read-spec].}
@scheme[read] for @scheme[read-spec]. The @schememodname[at-exp] and
@schememodname[planet] languages use the default
@scheme[read-spec].}
The result of @scheme[read-spec] is converted to a module path using
@scheme[module-path-parser]. If @scheme[module-path-parser] produces
@ -256,9 +269,9 @@ passed to @scheme[convert-read], @scheme[convert-read-syntax], or
@scheme[convert-get-info], respectively.
@margin-note{The @schememodname[at-exp] language supplies
@scheme[convert-read] and @scheme[convert-read-syntax] to add
@"@"-expression support to the current readtable before chaining to
the given procedures.}
@scheme[convert-read] and @scheme[convert-read-syntax] to add
@"@"-expression support to the current readtable before chaining to
the given procedures.}
The procedures generated by @scheme[make-meta-reader] are not meant
for use with the @schememodname[syntax/module-reader] language; they
@ -277,14 +290,14 @@ are meant to be exported directly.}
@emph{This function is deprecated; the
@schememodname[syntax/module-reader] language can be adapted using the
various keywords to arbitrary readers, and please use it instead.}
various keywords to arbitrary readers; please use it instead.}
Repeatedly calls @scheme[read] on @scheme[in] until an end of file,
collecting the results in order into @scheme[_lst], and derives a
@scheme[_name-id] from @scheme[(object-name in)]. The last five
@scheme[_name-id] from @scheme[(object-name in)]. The last five
arguments are used to construct the syntax object for the language
position of the module. The result is roughly
@schemeblock[
`(module ,_name-id ,mod-path ,@_lst)
`(module ,_name-id ,mod-path ,@_lst)
]}

View File

@ -28,7 +28,13 @@
(define (handle-image exp)
(printf ".") (flush-output)
(let ([result (parameterize ([current-namespace image-ns]) (eval exp))])
(let ([result
(with-handlers ([exn:fail?
(λ (x)
(printf "\nerror evaluating:\n")
(pretty-print exp)
(raise x))])
(parameterize ([current-namespace image-ns]) (eval exp)))])
(cond
[(image? result)
(let ([fn (exp->filename exp)])

View File

@ -8,8 +8,8 @@
(list
(list '(image-height (rectangle 100 100 "solid" "black")) 'val 100)
(list '(image-baseline (rectangle 100 100 "solid" "black")) 'val 100)
(list '(image-height (text "Hello" 24 "black")) 'val 24.0)
(list '(image-baseline (text "Hello" 24 "black")) 'val 18.0)
(list '(image-height (text "Hello" 24 "black")) 'val 41.0)
(list '(image-baseline (text "Hello" 24 "black")) 'val 31.0)
(list
'(image-height
(overlay (circle 20 "solid" "orange") (circle 30 "solid" "purple")))
@ -114,6 +114,76 @@
(ellipse 20 10 "solid" "black"))
'image
"28c73238138.png")
(list
'(underlay/xy
(underlay/xy
(ellipse 40 40 "solid" "gray")
10
15
(ellipse 10 10 "solid" "forestgreen"))
20
15
(ellipse 10 10 "solid" "forestgreen"))
'image
"201c231dce2.png")
(list
'(underlay/xy
(rectangle 20 20 "solid" "red")
-20
-20
(rectangle 20 20 "solid" "black"))
'image
"42f9f9e4cf.png")
(list
'(underlay/xy
(rectangle 20 20 "solid" "red")
20
20
(rectangle 20 20 "solid" "black"))
'image
"157ab5efca7.png")
(list
'(underlay/xy
(rectangle 20 20 "outline" "black")
20
0
(rectangle 20 20 "outline" "black"))
'image
"26bd803042c.png")
(list
'(underlay/align
"right"
"top"
(rectangle 50 50 "solid" "seagreen")
(rectangle 40 40 "solid" "silver")
(rectangle 30 30 "solid" "seagreen")
(rectangle 20 20 "solid" "silver"))
'image
"ff2fcb7b87.png")
(list
'(underlay/align
"middle"
"middle"
(rectangle 30 60 "solid" "orange")
(ellipse 60 30 "solid" "purple"))
'image
"2d1e52503d7.png")
(list
'(underlay
(ellipse 10 60 "solid" "red")
(ellipse 20 50 "solid" "black")
(ellipse 30 40 "solid" "red")
(ellipse 40 30 "solid" "black")
(ellipse 50 20 "solid" "red")
(ellipse 60 10 "solid" "black"))
'image
"28253f4c3c.png")
(list
'(underlay
(rectangle 30 60 "solid" "orange")
(ellipse 60 30 "solid" "purple"))
'image
"9858b8d5d.png")
(list
'(overlay/xy
(overlay/xy

View File

@ -318,6 +318,70 @@ other. The top and bottom pair of angles is @scheme[angle] and the left and righ
(ellipse 10 10 "solid" "forestgreen"))]
}
@defproc[(underlay [i1 image?] [i2 image?] [is image?] ...) image?]{
Underlays all of its arguments building a single image.
It behaves like @scheme[overlay], but with the arguments in the reverse order.
That is, the first argument goes
underneath of the second argument, which goes underneath the third argument, etc.
The images are all lined up on their upper-left corners.
@image-examples[(underlay (rectangle 30 60 "solid" "orange")
(ellipse 60 30 "solid" "purple"))
(underlay (ellipse 10 60 "solid" "red")
(ellipse 20 50 "solid" "black")
(ellipse 30 40 "solid" "red")
(ellipse 40 30 "solid" "black")
(ellipse 50 20 "solid" "red")
(ellipse 60 10 "solid" "black"))]
}
@defproc[(underlay/align [x-place x-place?] [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
Underlays all of its image arguments, much like the @scheme[underlay] function, but using
@scheme[x-place] and @scheme[y-place] to determine where the images are lined up. For example, if
@scheme[x-place] and @scheme[y-place] are both @scheme["middle"], then the images are lined up
on their centers.
@image-examples[(underlay/align "middle" "middle"
(rectangle 30 60 "solid" "orange")
(ellipse 60 30 "solid" "purple"))
(underlay/align "right" "top"
(rectangle 50 50 "solid" "seagreen")
(rectangle 40 40 "solid" "silver")
(rectangle 30 30 "solid" "seagreen")
(rectangle 20 20 "solid" "silver"))]
}
@defproc[(underlay/xy [i1 image?] [x real?] [y real?] [i2 image?]) image?]{
Constructs an image by underlaying @scheme[i1] underneath of @scheme[i2] after
shifting @scheme[i2] over by @scheme[x] pixels to the right and @scheme[y]
pixels down.
This is the same as @scheme[(overlay/xy i2 (- x) (- y) i1)].
@image-examples[(underlay/xy (rectangle 20 20 "outline" "black")
20 0
(rectangle 20 20 "outline" "black"))
(underlay/xy (rectangle 20 20 "solid" "red")
20 20
(rectangle 20 20 "solid" "black"))
(underlay/xy (rectangle 20 20 "solid" "red")
-20 -20
(rectangle 20 20 "solid" "black"))
(underlay/xy
(underlay/xy (ellipse 40 40 "solid" "gray")
10
15
(ellipse 10 10 "solid" "forestgreen"))
20
15
(ellipse 10 10 "solid" "forestgreen"))]
}
@defproc[(beside [i1 image?] [i2 image?] [is image?] ...) image?]{
Constructs an image by placing all of the argument images in a
horizontal row, aligned along their top edges.

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Some files were not shown because too many files have changed in this diff Show More