commit 6f39353a52bcf3af80d6f13100451dab73e08251
parent b5928162f5dd126bfd5a66b637ce1c0e10282608
Author: Eli Barzilay <eli@racket-lang.org>
Date: Fri, 13 Jul 2007 04:45:14 +0000
Added syntax properties to mark @-form datum and body number of subexprs
svn: r6902
original commit: 108b23e491e7965939f6b80e0b13b19363afc499
Diffstat:
2 files changed, 115 insertions(+), 43 deletions(-)
diff --git a/collects/scribble/doc.txt b/collects/scribble/doc.txt
@@ -570,34 +570,65 @@ matter, you can begin (or end) a line with a "@||".
@|| bar @|| --reads-as--> (foo " bar " "\n" " baz")
@|| baz}
-Finally, you might be need a verbatim-like environment, where the
-parsed body matches exactly the textual source. To make this
-possible, the @-parser uses syntax properties on the resulting syntax
-values. All items that are not physically in the Scribble source --
-newlines and indentation-spaces -- have a 'scribble property. An
-indentation string will have 'indentation as the value of this
-property, and a newline will have a '(newline S) value where S is the
-original newline string including spaces that precede and follow it
-(which includes the indentation for the following item). To implement
-a verbatim environment you need to drop indentation strings, and use
-the original newline strings instead of the single-newline string.
+* Syntax Properties
+
+The Scribble reader attaches properties to syntax objects. These
+properties might be useful in rare situations.
+
+Forms that Scribble reads is marked with a 'scribble property, and a
+value of a list of three elements: the first is 'form, the second is
+the number of items that were read from the datum part, and the third
+is the number of items in the body part (strings, sub-forms, and
+escapes). In both cases, a 0 means an empty datum/body part, and #f
+means that the corresponding part was omitted. If the form has
+neither parts, the property is not attached to the result. This
+property can be used to give different meanings to expressions from
+the datum and the body parts, for example, implicitly quoted keywords:
+
+ (define-syntax (foo stx)
+ (let ([p (syntax-property stx 'scribble)])
+ (syntax-case stx ()
+ [(_ x ...)
+ (and (pair? p) (eq? (car p) 'form) (even? (cadr p)))
+ (let loop ([n (/ (cadr p) 2)]
+ [as '()]
+ [xs (syntax->list #'(x ...))])
+ (if (zero? n)
+ #`(list 'foo `#,(reverse as) #,@xs)
+ (loop (sub1 n)
+ (cons #`(#,(car xs) ,#,(cadr xs)) as)
+ (cddr xs))))])))
+ @foo[x 1 y (* 2 3)]{blah}
+ --> (foo ((x 1) (y 6)) "blah")
+
+In addition, the Scribble parser uses syntax properties to mark syntax
+items that are not physically in the original source -- indentation
+spaces and newlines. Both of these will have a 'scribble property; an
+indentation string of spaces will have 'indentation as the value of
+the property, and a newline will have a '(newline S) value where S is
+the original newline string including spaces that precede and follow
+it (which includes the indentation for the following item). This can
+be used to implement a verbatim environment: drop indentation strings,
+and use the original source strings instead of single-newline string.
Here is an example of this.
(define-syntax (verb stx)
(syntax-case stx ()
[(_ cmd item ...)
- #`(cmd .
- #,(let loop ([items (syntax->list #'(item ...))])
- (if (null? items)
- '()
- (let* ([fst (car items)]
- [prop (syntax-property fst 'scribble)]
- [rst (loop (cdr items))])
- (cond [(not prop) (cons fst rst)]
- [(eq? prop 'indentation) rst]
- [else (cons (datum->syntax-object
- fst (cadr prop) fst)
- rst)])))))]))
+ #`(cmd
+ #,@(let loop ([items (syntax->list #'(item ...))])
+ (if (null? items)
+ '()
+ (let* ([fst (car items)]
+ [prop (syntax-property fst 'scribble)]
+ [rst (loop (cdr items))])
+ (cond [(eq? prop 'indentation) rst]
+ [(not (and (pair? prop)
+ (eq? (car prop) 'newline)))
+ (cons fst rst)]
+ [else (cons (datum->syntax-object
+ fst (cadr prop) fst)
+ rst)])))))]))
@verb[string-append]{
foo
bar
diff --git a/collects/scribblings/scribble/reader.scrbl b/collects/scribblings/scribble/reader.scrbl
@@ -631,18 +631,59 @@ matter, you can begin (or end) a line with a "@||".
@|| baz}
}===|
-Finally, you might be need a verbatim-like environment, where the
-parsed body matches exactly the textual source. To make this
-possible, the @"@"-parser uses syntax properties on the resulting
-syntax values. All items that are not physically in the Scribble
-source---newlines and indentation-spaces---have a 'scribble property.
-An indentation string will have @scheme['indentation] as the value of
-this property, and a newline will have a @scheme['(newline S)] value
-where S is the original newline string including spaces that precede
-and follow it (which includes the indentation for the following item).
-To implement a verbatim environment you need to drop indentation
-strings, and use the original newline strings instead of the
-single-newline string. Here is an example of this.
+@subsubsub*section{Syntax Properties}
+
+The Scribble reader attaches properties to syntax objects. These
+properties might be useful in rare situations.
+
+Forms that Scribble reads is marked with a @scheme['scribble]
+property, and a value of a list of three elements: the first is
+@scheme['form], the second is the number of items that were read from
+the datum part, and the third is the number of items in the body part
+(strings, sub-forms, and escapes). In both cases, a @scheme[0] means
+an empty datum/body part, and @scheme[#f] means that the corresponding
+part was omitted. If the form has neither parts, the property is not
+attached to the result. This property can be used to give different
+meanings to expressions from the datum and the body parts, for
+example, implicitly quoted keywords:
+
+@; FIXME: a bit of code duplication here
+@def+int[
+ (define-syntax (foo stx)
+ (let ([p (syntax-property stx 'scribble)])
+ (syntax-case stx ()
+ [(_ x ...)
+ (and (pair? p) (eq? (car p) 'form) (even? (cadr p)))
+ (let loop ([n (/ (cadr p) 2)]
+ [as '()]
+ [xs (syntax->list #'(x ...))])
+ (if (zero? n)
+ (with-syntax ([attrs (reverse as)]
+ [(x ...) xs])
+ #'(list 'foo `attrs x ...))
+ (loop (sub1 n)
+ (cons (with-syntax ([key (car xs)]
+ [val (cadr xs)])
+ #'(key ,val))
+ as)
+ (cddr xs))))])))
+(eval:alts
+ (code:line
+ #, @tt["@foo[x 1 y (* 2 3)]{blah}"])
+ @foo[x 1 y (* 2 3)]{blah})
+]
+
+In addition, the Scribble parser uses syntax properties to mark syntax
+items that are not physically in the original source --- indentation
+spaces and newlines. Both of these will have a @scheme['scribble]
+property; an indentation string of spaces will have
+@scheme['indentation] as the value of the property, and a newline will
+have a @scheme['(newline S)] value where @scheme[S] is the original
+newline string including spaces that precede and follow it (which
+includes the indentation for the following item). This can be used to
+implement a verbatim environment: drop indentation strings, and use
+the original source strings instead of single-newline string. Here is
+an example of this.
@; FIXME: a bit of code duplication here
@def+int[
@@ -656,21 +697,21 @@ single-newline string. Here is an example of this.
(let* ([fst (car items)]
[prop (syntax-property fst 'scribble)]
[rst (loop (cdr items))])
- (cond [(not prop) (cons fst rst)]
- [(eq? prop 'indentation) rst]
+ (cond [(eq? prop 'indentation) rst]
+ [(not (and (pair? prop)
+ (eq? (car prop) 'newline)))
+ (cons fst rst)]
[else (cons (datum->syntax-object
fst (cadr prop) fst)
rst)])))))]))
(eval:alts
-
(code:line
#, @tt["@verb[string-append]{"]
#, @tt[" foo"]
#, @tt[" bar"]
#, @tt["}"])
-
- @verb[string-append]{
- foo
- bar
- })
+ @verb[string-append]{
+ foo
+ bar
+ })
]