Documentation, changed (begin x ...) to produce a splicing list, not a list (and documented accordingly)

This commit is contained in:
Georges Dupéron 2017-02-03 15:45:49 +01:00
parent 3b99a0ce02
commit 68f5d38902
9 changed files with 453 additions and 81 deletions

View File

@ -9,7 +9,8 @@
"alexis-util"
"scope-operations"))
(define build-deps '("scribble-lib"
"racket-doc"))
"racket-doc"
"scribble-math"))
(define scribblings '(("scribblings/subtemplate.scrbl" () (parsing-library))))
(define pkg-desc "Various enhancements on syntax templates")
(define version "1.0")

4
light.rkt Normal file
View File

@ -0,0 +1,4 @@
#lang racket
(require subtemplate/private/template-subscripts)
(provide subtemplate
quasisubtemplate)

View File

@ -4,23 +4,30 @@
stxparse-info/parse
subtemplate/private/unsyntax-preparse
subtemplate/private/top-subscripts
(except-in stxparse-info/parse/experimental/template
template
quasitemplate
template/loc
quasitemplate/loc
?@
??)
(only-in racket/base [... ])
(only-in stxparse-info/parse [...+ …+]))
(provide
;; ddd-forms
?@ ?@@ ?? ?attr ?cond ?if begin define let #%app #%intef-begin
?@ ?@@ ?? ?attr ?cond ?if begin let #%app #%intdef-begin
;; stxparse-info/case
(all-from-out stxparse-info/case)
;; stxparse-info/parse
(all-from-out stxparse-info/parse)
;; stxparse-info/parse/experimental/template
(all-from-out stxparse-info/parse/experimental/template)
;; subtemplate/private/unsyntax-preparse
(rename-out
[template-ddd template]
[subtemplate-ddd subtemplate]
[quasitemplate-ddd quasitemplate]
[quasisubtemplate-ddd quasisubtemplate]
[subtemplate-ddd syntax]
[quasisubtemplate-ddd quasisyntax])
[quasisubtemplate-ddd quasisubtemplate])
;; subtemplate/private/top-subscripts
;; => #%top
(all-from-out subtemplate/private/top-subscripts)

5
override.rkt Normal file
View File

@ -0,0 +1,5 @@
#lang racket/base
(require subtemplate)
(provide (all-from-out subtemplate)
(rename-out [subtemplate syntax]
[quasisubtemplate quasisyntax]))

View File

@ -1,8 +1,7 @@
#lang racket/base
(provide begin
define
let
(rename-out [begin #%intef-begin])
#%intdef-begin
(rename-out [app #%app])
??
?if
@ -91,15 +90,17 @@
#,(nest* (ddd %) e ooo*)))
(pattern {~seq e :ooo+}
;#:with expanded #`(apply values #,(ddd* e ooo*))
#:with expanded (ddd* e ooo*))
#:with expanded #`(splicing-list #,(ddd* e ooo*)))
(pattern other
#:with expanded #'other)))
(define-syntax/parse (begin stmt:stmt )
(template (-begin (?@ stmt.expanded) )))
(define-syntax #%intdef-begin (make-rename-transformer #'begin))
(define-syntax/parse (let {~optional name:id} ([var . val] ) . body)
(template (-let (?? name) ([var (begin . val)] ) (begin . body))))
(template (-let (?? name) ([var (begin . val)] ) (#%intdef-begin . body))))
(begin-for-syntax
(define-splicing-syntax-class arg

83
scribblings/light.scrbl Normal file
View File

@ -0,0 +1,83 @@
#lang scribble/manual
@require[scriblib/footnote
@for-label[subtemplate/light
syntax/parse/experimental/template
racket/base]]
@(begin
(module m racket/base
(require scribble/manual
(for-template subtemplate)
(for-syntax racket/base
racket/syntax))
(define-syntax (mk stx)
(syntax-case stx ()
[(_ id)
(with-syntax ([full: (format-id #'id "full:~a" #'id)])
#'(begin
(define full: @racket[id])
(provide full:)))]))
(define-syntax-rule (mk* id ...) (begin (mk id) ...))
(mk* subtemplate ?@@ ?attr ?cond ?if))
(require 'm))
@title{Lightweight Subtemplate}
@defmodule[subtemplate/light]{
This module only provides stripped-down versions of @racket[subtemplate] and
@racket[quasisubtemplate], without overriding @racket[syntax] and
@racket[quasisyntax]. Note that some features will not work when using these
versions. Prefer using @racket[(require subtemplate)] instead.
Another limitation is that subscripted identifiers are not searched for
within unquoted parts of the template.
Note that you need to require @racketmodname[stxparse-info/parse] and
@racketmodname[stxparse-info/case], otherwise @racket[subtemplate] and
@racket[quasisubtemplate] will not be able to detect which pattern variables
are bound (and therefore will be unable to know from which @racket[xᵢ] an
@racket[yᵢ] should be derived.}
@defform*[{(subtemplate template)
(subtemplate template #:properties (prop ...))}
#:contracts
([prop identifier?])]{
Like @full:subtemplate from @racketmodname[subtemplate], but with a few
features missing (@full:?@@ @full:?attr @full:?cond @full:?if).}
@defform*[{(subtemplate template)
(subtemplate template #:properties (prop ...))}
#:contracts
([prop identifier?])]{
Like @full:subtemplate from @racketmodname[subtemplate], but with a few
features missing. The utilities @full:?@@ @full:?attr @full:?cond @full:?if
are not taken into account, and @racket[unsyntax] completely escapes the
ellipses.
Note that the syntax pattern variables must be matched with one of the
patched forms from @racketmodname[stxparse-info/parse] or
@racketmodname[stxparse-info/case], instead of the syntax pattern-matching
forms from @racketmodname[syntax/parse] or @racketmodname[racket/base],
respectively.}
@defform*[{(quasisubtemplate template)
(quasisubtemplate template #:properties (prop ...))}
#:contracts
([prop identifier?])]{
Like @full:subtemplate from @racketmodname[subtemplate], but with a few
features missing. The utilities @full:?@@ @full:?attr @full:?cond @full:?if
are not taken into account, and @racket[unsyntax] completely escapes the
ellipses
Another limitation is that subscripted identifiers are not searched for
within unquoted parts of the template.
Note that the syntax pattern variables must be matched with one of the
patched forms from @racketmodname[stxparse-info/parse] or
@racketmodname[stxparse-info/case], instead of the syntax pattern-matching
forms from @racketmodname[syntax/parse] or @racketmodname[racket/base],
respectively. }

View File

@ -1,13 +1,170 @@
#lang scribble/manual
@require[scriblib/footnote
@for-label[subtemplate/private/template-subscripts
syntax/parse/experimental/template
racket/base]]
@require[racket/require
scriblib/footnote
scribble-math
@for-label[subtemplate
(only-in syntax/parse/experimental/template)
(subtract-in racket/base subtemplate)]]
@title{Subtemplate}
@(begin
(module m racket/base
(require scribble/manual
(for-template syntax/parse
syntax/parse/experimental/template
racket/syntax)
(for-syntax racket/base
racket/syntax))
(define-syntax (mk stx)
(syntax-case stx ()
[(_ id)
(with-syntax ([orig: (format-id #'id "orig:~a" #'id)])
#'(begin
(define orig: @racket[id])
(provide orig:)))]))
(define-syntax-rule (mk* id ...) (begin (mk id) ...))
(mk* syntax-parse syntax-case with-syntax template quasitemplate syntax
unsyntax quasisyntax ?? ?@ template/loc quasitemplate/loc #%app
#%top begin let))
(require 'm))
@title[#:style (with-html5 manual-doc-style)]{Subtemplate}
@author[@author+email["Georges Dupéron" "georges.duperon@gmail.com"]]
@defmodule[subtemplate/private/template-subscripts]
This library should be considered experimental. Although most of the syntax
should work in the same way in future versions, the behaviour of some corner
cases may change, as I try to find the best semantics.
Also, this library requires some patched versions of @racket[syntax-parse] and
@orig:syntax-case, as these do not offer the hooks needed to implement
@racket[subtemplate]. Unfortunately, as the official implementations of
@racket[syntax-parse] and @racket[syntax-case] evolve, compatibility issues
may arise.
If you desire to use this library, please drop me an e-mail (my address is
below the title), so that I can keep you informed of upcoming changes, see if
these are likely to cause problems in your code.
Finally, If the maintenance burden is too high, I might drop the compatibility
with @racketmodname[syntax/parse] and @|orig:syntax-case|.
@section{The main @racketmodname[subtemplate] module}
@defmodule[subtemplate]{
The @racketmodname[subtemplate] module provides @racket[subtemplate], an
alternative to @racketmodname[syntax/parse]'s @orig:template, which
supports several convenience features:
@itemlist[
@item{When an identifier @racket[yᵢ] is encountered in a template, it is
automatically defined as a pattern variable containing temporary identifiers.
This avoids the need to manually call @racket[generate-temporaries].
The generated temporary identifiers will be based on a @racket[xᵢ] pattern
variable with the same subscript as @racket[yᵢ], and @racket[yᵢ] will be
nested at the same ellipsis depth as @racket[xᵢ].
The identifiers @racket[xᵢ] and @racket[yᵢ] must end wit the same subscript,
which must be a sequence of unicode subscript characters picked among
@tt{ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ ᵦ ᵧ ᵨ ᵩ ᵪ}. Alternatively, the
subscript may be specified with an underscore followed by any characters
other than an underscore. The two notations are equivalent, in the sense that
@racket[yᵦ] and @racket[y_β] are interpreted in the same way, and if both
appear within a template, they will use the same sequence of temporary
identifiers generated from an @racket[xᵦ] or @racket[x_β].}
@item{The value of pattern variables is automatically extracted when the
variable does not appear in a syntax template. Note that since the syntax
object is transformed into a plain datum, source locations and lexical
contexts are lost. This is a trade-off between better error messages, which
make sure that source locations and lexical context are not lost by accident
(no automatic @racket[syntax-e]), and more concise code (with automatic
@racket[syntax-e]). It is possible that a future version may require explicit
syntax-e, possibly via a concise shorthand like @racket[unquote] (@tt{,}) or
@racket[unsyntax] (@tt{#,}), if this feature turns out to be too dangerous in
practice.}
@item{Ellipses work outside of syntax templates, and can be used after
definitions and expressions.
@itemlist[
@item{The result of an expression under @${n} ellipses is a
@${\text{nested}^n} list, where the expression is evaluated for
each value of the pattern variables located within. In other words,
@racket[(x ...)] should produce a value similar to
@racket[(syntax->datum #'(x ...))]. However, it is possible to actually
manipulate the value, e.g. by writing @racket[(+ x 1) ...]. It is possible
to write @${m} ellipses in a row (which has the effect of flattening
@${m - 1} levels in the result list). It is also possible to nest the use
of these ellipses, e.g. with @racket[(x ...) ...], which keeps the
structure of the nested lists in the result.}
@item{When a definition form (@racket[define] or @racket[define/with-syntax]
for now) is followed by @${n} ellipses, then the defined identifier is a
@${\text{nested}^n} list, or a syntax pattern variable with an ellipsis
depth of @${n}. The expression is evaluated for each value of the template
variables it contains. Note that the structure of the nested lists is not
flattened, despite the fact that the ellipses are written one after
another. This is because it is usually the desired outcome, and nesting
parentheses around the definition form would produce rather unreadable
code.}
@item{These ellipses can also be used ``inline'' within function calls
(@racketmodname[subtemplate] overrides @racket[#%app] to achieve this). For
example: @racket[(/ (+ x ...) (length x))] would compute the average of
@racket[(syntax->datum #'(x ...))]}
@item{Subscripted identifiers should also work in expressions
(@racketmodname[subtemplate] overrides @racket[#%top] to achieve this),
although this seems less useful, as the temporary identifiers loose their
lexical context information in that way.}
@item{The splicing forms @racket[?@] and @racket[?@@], as well as
@racket[??], @racket[?if] and @racket[?cond] work within expressions, and
can be used to splice values into the argument list when calling a
function. For example, @racket[(+ 1 (?@ l) 3)] would splice the values of
the list @racket[l] into the argument list, effectively calling
@racket[(+ 1 97 98 99 3)] if @racket[l] was equal to
@racket[#'(97 98 99)]. Additionnally, it is possible to append a list
at the end of the argument list, with the syntax @racket[(+ 1 2 . l)].}
@item{It is possible to create a syntax object based on one of the iterated
pattern variables within the expression-ellipses, for example using
@racket[(#'x ...)].}]}
@item{Within a @racket[subtemplate] and a @racket[quasisubtemplate], it is
possible to use @racket[unsyntax] and @racket[unsyntax-splicing] to escape
from the template. Within the escaped expression, the ellipsis depth of the
template is conserved, making it possible to write
@RACKET[(subtemplate (#,(+ x 1) ...))], for example.
The usual behaviour, which resets the ellipsis count to 0, can be obtained
with @RACKET[#,,expr] (that is, @RACKET[(unsyntax (unquote expr))]) for an
@racket[unsyntax]-like escape. An @racket[unsyntax-splicing]-style escape
can be obtained with @RACKET[#,,@expr] or @RACKET[#,@,expr] (that is,
@RACKET[(unsyntax (unquote-splicing expr))] or
@RACKET[(unsyntax-splicing (unquote expr))]).}
@item{Several utilities in the spirit of @racket[??] and @racket[?@] are
provided, namely @racket[?@@], @racket[?attr] @racket[?cond] and
@racket[?if].}
@item{All features (subscripted identifiers, dotted expressions and
definitions, and the ellipsis-preserving @racket[unsyntax]) should work well
with omitted elements in attributes, as created by
@racket[~optional] or @racket[~or] in @racket[syntax-parse].}]}
@subsection{Modules re-provided by @racketmodname[subtemplate]}
The @racketmodname[subtemplate] library needs some cooperation from
@racket[syntax-case], @racket[syntax-parse] and similar forms. For this
reason, some patched versions are defined in the @racketmodname[stxparse-info]
library. @racket[subtemplate] cannot work properly if the right modules are
loaded. To make it easier to use @racketmodname[subtemplate], it re-provides
the modules that need to be loaded for it to function properly.
The @racketmodname[subtemplate] module re-provides
@racketmodname[stxparse-info/parse], @racketmodname[stxparse-info/case] and
the parts of @racketmodname[racket/syntax] which are not overridden by
@racketmodname[stxparse-info/case].
The @racketmodname[subtemplate/private/override] module also re-provides
@racketmodname[stxparse-info/parse/experimental/template], but without
@orig:template, @orig:quasitemplate, @orig:?? and @orig:?@, which are remapped
to their equivalents from this library, and without @orig:template/loc] and
@orig:quasitemplate/loc, which do not have an equivalent yet.
@subsection{New and overridden bindings provided by @racketmodname[subtemplate]}
@defform*[{(subtemplate template)
(subtemplate template #:properties (prop ...))}
@ -15,12 +172,7 @@
([prop identifier?])]{
Like @racket[template], but automatically derives identifiers for any
@racket[yᵢ …] which is not bound as a syntax pattern variable, based on a
corresponding @racket[xᵢ …] which is bound as a syntax pattern variable.
Note that the syntax pattern variables must be matched with one of the
patched forms from @racket[stxparse-info/parse] or
@racket[stxparse-info/case], instead of the syntax pattern-matching forms from
@racket[syntax/parse] or @racket[racket/base], respectively.}
corresponding @racket[xᵢ …] which is bound as a syntax pattern variable.}
@defform*[{(quasisubtemplate template)
(quasisubtemplate template #:properties (prop ...))}
@ -29,31 +181,134 @@
Like @racket[quasitemplate], but automatically derives identifiers for any
@racket[yᵢ …] which is not bound as a syntax pattern variable, based on a
corresponding @racket[xᵢ …] which is bound as a syntax pattern variable, in
the same way as @racket[subtemplate].
the same way as @racket[subtemplate].}
Note that the syntax pattern variables must be matched with one of the
patched forms from @racket[stxparse-info/parse] or
@racket[stxparse-info/case], instead of the syntax pattern-matching forms from
@racket[syntax/parse] or @racket[racket/base], respectively.
}
@defform*[{(template template)
(template template #:properties (prop ...))}
#:contracts
([prop identifier?])]{
Like @racket[subtemplate], but does not automatically generate pattern
variables based on their subscript. The other features still work
(ellipsis-preserving escapes with @racket[unsyntax], support for @racket[?@@],
@racket[?attr], @racket[?cond] and @racket[?if]).}
@defform*[{(quasitemplate template)
(quasitemplate template #:properties (prop ...))}
#:contracts
([prop identifier?])]{
Like @racket[quasisubtemplate], but does not automatically generate pattern
variables based on their subscript. The other features still work
(ellipsis-preserving escapes with @racket[unsyntax], support for @racket[?@@],
@racket[?attr], @racket[?cond] and @racket[?if]).}
@defform[#:kind "procedure"
(?@ . expr)]{Splices the @racket[expr] into the surrounding form
(which must be a function application). If the surrounding form is a
@racket[begin], @racket[let], or @racket[#%intdef-begin], then the the
splicing lists are not processed, but may be processed later by using the
splicing-list value as an argument to a function.
Also works in @racket[template], @racket[subtemplate] and their derivatives.}
@defform[#:kind "procedure"
(?@@ . expr)]{Appends all the lists contained within @racket[expr],
and splices the resulting list into the surrounding form. If the
surrounding form is a @racket[begin], @racket[let], or
@racket[#%intdef-begin], then the splicing lists are not processed, but may be
processed later by using the splicing-list value as an argument to a
function.
Also works in @racket[template], @racket[subtemplate] and their derivatives.}
@defform*[[(?? alt)
(?? alt else)]]{
Executes @racket[alt], if none of the template variables within is omitted
(i.e. bound to @racket[#false] for the current ellipsis iteration). Otherwise,
executes @racket[else]. If @racket[else] is omitted, it defaults to
@racket[(?@)], i.e. the empty splice.
Also works in @racket[template], @racket[subtemplate] and their derivatives.}
@defform*[[(?if condition alt)
(?if condition alt else)]]{
Generalisation of @racket[??]. If none of the template variables within
@racket[condition] is omitted (i.e. bound to @racket[#false] for the current
ellipsis iteration), then @racket[alt] is executed. Otherwise, @racket[else]
is executed.
Also works in @racket[template], @racket[subtemplate] and their derivatives.}
@defform[(?attr condition)]{Shorthand for @racket[?if condition #t #f]
Also works in @racket[template], @racket[subtemplate] and their derivatives.}
@defform*[#:literals (else)
[(?cond [condition alt] …)
(?cond [condition alt] … [else alt])]]{
Equivalent to nested uses of @racket[?if]. If no @racket[else] clause is
supplied, then @racket[(?@)], i.e. the empty splice, is used instead.}
@defform[(begin body ...)]{
Overridden version of @|orig:begin|. Supports ellipses after definitions
(using @racket[define] and @racket[define-syntax]). Supports ellipses after
expressions, in which case the results are grouped into a splicing list, which
makes it possible to write @racket[(+ (begin x ...))] and obtain the same
result as with @racket[(+ x ...)].}
@defform*[[(let ([var val] …) . body)
(let name ([var val] …) . body)]]{
Overridden version of @|orig:let|. Supports ellipses in the @racket[body]
after definitions (using @racket[define] and @racket[define-syntax]). Supports
ellipses after expressions both in the @racket[body] and in the @racket[val].
In both cases, the results are grouped into a splicing list, which makes it
possible to write @racket[(let ([vs x ...]) (+ vs))] and obtain the same
result as with @racket[(+ x ...)].}
@defform[(#%intdef-begin . body)]{
Equivalent to @racket[begin] from @racketmodname[subtemplate], but assumes
that it appears directly within the body of a @racket[let] or similar form.
Third-party macros can cooperate with @racketmodname[subtemplate], allowing
its features to be used where a sequence of statements is expected. To achieve
that, the macro would need to detect with @racket[identifier-binding] and
@racket[syntax-local-introduce] whether @racket[#%intdef-begin] is bound at the
macro's use-site. If this is the case, then the macro could use
@racket[#%intdef-begin] instead of @racket[begin].}
@defform*[[(#%app f arg ... . rest)
(#%app val ooo ...+ expression ...+ . rest)]]{
Overridden version of @|orig:#%app|, which supports ellipses in the argument
list. When one of the arguments contains a splicing list, the list's values
are spliced into the argument list.
If the first argument is an ellipsis, the @racket[list] function is
implicitly used, and the first element following @racket[#%app] is interpreted
as an argument under ellipses.
A variable appearing in tail position after a dot is appended to the argument
list, and splicing-lists within are handled.}
@defform[(#%top . var)]{Overridden version of @|orig:#%top|, which is used to
automatically derive temporary identifiers in expressions. When an unbound
variable @racket[yᵢ] is used and a matching pattern variable @racket[xᵢ] with
the same subscript is bound. Note that if a variable @racket[yᵢ] is already
bound to some value, no attempt will be made to derive temporary identifiers
for that variable. In contrast, if the identifier @racket[yᵢ] appears, quoted
by a @racket[subtemplate], then subtemplate will attempt to derive it even if
it is bound (unless it is bound as a pattern variable).}
@defidform[…]{Alias for @racket[...]}
@defidform[…+]{Alias for @racket[...+]}
@section{Overriding the default @racket[#'…] and @racket[#`…]}
@defmodule[subtemplate/private/override]
The @racketmodname[subtemplate/private/override] module re-provides
@racket[subtemplate] as @racket[syntax], and @racket[quasisubtemplate] as
@racket[quasisyntax]. This allows @racketmodname[subtemplate] to be used via
the reader shorthands @racket[#'…] and @racket[#`…].
The @racketmodname[subtemplate/private/override] module also re-provides
@racketmodname[stxparse-info/parse] and @racketmodname[stxparse-info/case].
The @racketmodname[subtemplate/private/override] module also re-provides
@racketmodname[stxparse-info/parse/experimental/template], but without
@racket[template] and @racket[quasitemplate], which are remapped to their
@racket[sub] equivalents, and without @racket[template/loc] and
@racket[quasitemplate/loc], which do not have a @racket[sub] equivalent yet.
@defmodule[subtemplate/override]{
The @racketmodname[subtemplate/override] module provides the same bindings as
@racketmodname[subtemplate], but also re-provides @racket[subtemplate] as
@racket[syntax], and @racket[quasisubtemplate] as @racket[quasisyntax]. This
allows @racketmodname[subtemplate] to be used via the reader shorthands
@racket[#'…] and @racket[#`…].}
@section{Limitations}
@ -61,8 +316,7 @@ The derived subscripted identifiers have to be syntactically present within
the template. In particular, if a template metafunction generates a part of a
template containing @racket[yᵢ], it will work only if @racket[yᵢ] is also
present in the "main" part of the template (possibly as an argument to the
template metafunction, or elsewhere). Subscripted identifiers are not searched
for within unquoted parts of the template.
template metafunction, or elsewhere).
Currently, template metafunctions defined with
@racketmodname[stxparse-info/parse/experimental/template] are not compatible
@ -77,12 +331,18 @@ from the fact that @racket[subtemplate] cannot derive @racket[yᵢ] from
@racketmodname[syntax/parse]), please report them to
@url{https://github.com/jsmaniac/subtemplate/issues}.
The code generated by @racket[subtemplate] is not very optimised, so
compile-time and run-time performance will not be as good as with
@racket[syntax] or @racket[template].
The code generated by @racket[subtemplate] is not optimised, so compile-time
and run-time performance will not be as good as with @racket[syntax] or
@racket[template].
Despite the rather extensive test suite, there are probably a few bugs lurking,
please report them to @url{https://github.com/jsmaniac/subtemplate/issues}.
The expression splicing-lists are not recognised by templates, and it is not
possible for a template to produce a ``splicing syntax object'' (instead, an
error is raised if a @racket[?@] causes a template to return more than one
syntax object).
Despite the rather extensive test suite, there are likely still some bugs
lurking, please report them to
@url{https://github.com/jsmaniac/subtemplate/issues}.
@subsection{Omitted elements in attributes (via @racket[~optional])}
@ -105,4 +365,6 @@ If new pattern variables with the same subscript are introduced after a
generated variable was used, they should have the same structure (i.e. missing
sublists in the same positions). Otherwise, the derived variable generated by
@racket[subtemplate] would not contain the same elements before and after that
new pattern variable was introduced.
new pattern variable was introduced.
@include-section{light.scrbl}

View File

@ -169,45 +169,53 @@
'(1 2 3 4 5 6))
;; Implicit (list _), could also be changed to an implicit (values).
(check-equal? (syntax-parse #'(([1 2 3] [4 5 6]) [a])
[(([x ] ) [y ])
x ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'(([1 2 3] [4 5 6]) [a])
[(([x ] ) [y ])
x ]))
'(1 2 3 4 5 6))
;; TODO: expr … inside begin and let
(check-equal? (syntax-case #'((1 2 3) (4 5)) ()
[((x ) )
(let ()
(list (length (syntax->list #'(x )))
(+ (syntax-e #'x) 3) )
)])
(check-equal? (list ;; unwrap the splice
(syntax-case #'((1 2 3) (4 5)) ()
[((x ) )
(let ()
(list (length (syntax->list #'(x )))
(+ (syntax-e #'x) 3) )
)]))
'([3 4 5 6]
[2 7 8]))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
x ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
x ]))
'(1 2 3 4 5 6))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(x ) ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(x ) ]))
'((1 2 3) (4 5 6)))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
((list x) ) ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
((list x) ) ]))
'(((1) (2) (3)) ((4) (5) (6))))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
((+ x 10) ) ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
((+ x 10) ) ]))
'((11 12 13) (14 15 16)))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(begin ((+ x 10) ) )])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(begin ((+ x 10) ) )]))
'((11 12 13) (14 15 16)))
(check-equal? (syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(define/with-syntax y (+ x 10))
y ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'([1 2 3] [4 5 6])
[([x ] )
(define/with-syntax y (+ x 10))
y ]))
'(11 12 13 14 15 16))
;; Implicit apply with (+ y … …)

View File

@ -6,9 +6,10 @@
syntax/macro-testing
phc-toolkit/untyped)
(check-equal? (syntax-parse #'(1 #:kw 3)
[({~and {~or x:nat #:kw}} )
(?? x 'missing) ])
(check-equal? (list ;; unwrap the splice
(syntax-parse #'(1 #:kw 3)
[({~and {~or x:nat #:kw}} )
(?? x 'missing) ]))
'(1 missing 3))
(check-equal? (syntax-parse #'(1 #:kw 3)