Skip to content

Commit 5b3ec9b

Browse files
committed
Add an generic quasiquote to data/collection/experimental/quasi
1 parent d647e8c commit 5b3ec9b

File tree

6 files changed

+142
-4
lines changed

6 files changed

+142
-4
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#lang scribble/manual
2+
3+
@(require
4+
racket/require
5+
(for-label (subtract-in
6+
(combine-in
7+
racket/base
8+
racket/list
9+
racket/set
10+
racket/dict
11+
racket/math)
12+
data/collection)
13+
(prefix-in base: racket/base)
14+
data/collection
15+
racket/function
16+
racket/generic
17+
racket/contract
18+
racket/stream
19+
racket/string
20+
racket/match
21+
racket/generator)
22+
scribble/core
23+
"../private/utils.rkt")
24+
25+
@(module racket-forms racket/base
26+
(require (for-label racket/base)
27+
scribble/manual)
28+
(provide racket:quasiquote)
29+
(define racket:quasiquote
30+
(racket quasiquote)))
31+
@(require 'racket-forms)
32+
33+
@title[#:tag "experimental"]{Experimental Forms and Functions}
34+
35+
@(define (yellow . content)
36+
(make-element (make-style #f (list (make-background-color-property "yellow"))) content))
37+
38+
@nested[#:style 'inset]{
39+
@yellow{@bold{WARNING}}: The following forms and functions are @emph{experimental}; compatibility
40+
will not be maintained.}
41+
42+
@section{Generic Quasiquotation}
43+
44+
@defmodule[data/collection/experimental/quasi]
45+
46+
@defform[(quasiquote datum)]{
47+
Equivalent to @racket:quasiquote from @racketmodname[racket/base], except that uses of
48+
@racket[unquote-splicing] accept arbitrary @racket[sequence?] values instead of only lists.
49+
50+
Note that this handling only applies to uses of @racket[unquote-splicing], not @racket[unquote], so
51+
@racket[`(1 @#,racketvalfont{.} ,_more)] will produce different results from @racket[`(1 ,@_more)]
52+
when @racket[_more] is a non-list sequence.
53+
54+
@(coll-examples
55+
`(1 2 ,(+ 1 2))
56+
`(Z = ,@(take 5 (naturals)) ...)
57+
`#s(prefab i ,@#(ii iii iv) v))}

collections-doc/scribblings/data/collection/collection/reference.scrbl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
racket/string
2020
racket/match
2121
racket/generator)
22-
scribble/eval
2322
"../private/utils.rkt")
2423

2524
@title[#:tag "collections-api"]{API Documentation}

collections-doc/scribblings/data/collection/collections.scrbl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#lang scribble/manual
22

3-
@(require
4-
"private/utils.rkt")
3+
@(require "private/utils.rkt")
54

65
@title{Generic Collections}
76

@@ -20,4 +19,5 @@ this reason, this @emph{may} not be a drop-in replacement for existing code.
2019

2120
@include-section["collection/introduction.scrbl"]
2221
@include-section["collection/examples.scrbl"]
23-
@include-section["collection/reference.scrbl"]
22+
@include-section["collection/reference.scrbl"]
23+
@include-section["collection/experimental.scrbl"]

collections-doc/scribblings/data/collection/private/utils.rkt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#:lang 'racket
1919
'(racket/generic
2020
data/collection
21+
data/collection/experimental/quasi
2122
racket/generator)))
2223

2324
(define-syntax-rule (coll-interaction . body)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#lang racket/base
2+
3+
(require (for-syntax racket/base)
4+
data/collection
5+
syntax/parse/define
6+
(only-in racket/base [cons pair]))
7+
8+
(provide quasiquote unquote unquote-splicing)
9+
10+
(begin-for-syntax
11+
(define-syntax-class qqed
12+
#:attributes [expr]
13+
#:description #f
14+
#:literals [unquote]
15+
[pattern (uq:unquote ~! e:expr)
16+
#:attr expr (syntax-property #'e
17+
'disappeared-use
18+
(syntax-local-introduce #'uq))]
19+
[pattern x
20+
#:attr expr #'(quasiquote x)])
21+
22+
(define-syntax-class qqed/splicing
23+
#:attributes [expr]
24+
#:description #f
25+
#:literals [unquote-splicing]
26+
[pattern (uqs:unquote-splicing ~! e)
27+
#:declare e (expr/c #'sequence?
28+
#:macro 'unquote-splicing
29+
#:name "argument")
30+
#:attr expr (syntax-property #'e.c
31+
'disappeared-use
32+
(syntax-local-introduce #'uqs))]
33+
[pattern e:qqed
34+
#:attr expr #`(list #,(attribute e.expr))]))
35+
36+
(define-syntax-parser quasiquote
37+
[(_ (x:qqed/splicing ...))
38+
#'(sequence->list (append x.expr ...))]
39+
[(_ #(x:qqed/splicing ...))
40+
#'(extend #() (append x.expr ...))]
41+
[(_ (a:qqed . b:qqed))
42+
#'(pair a.expr b.expr)]
43+
[(_ prefab)
44+
#:when (prefab-struct-key (syntax-e #'prefab))
45+
#:with key (prefab-struct-key (syntax-e #'prefab))
46+
#:with #(_ x:qqed/splicing ...) (struct->vector (syntax-e #'prefab))
47+
#'(apply make-prefab-struct 'key (append x.expr ...))]
48+
[(_ hsh)
49+
#:do [(define datum (syntax-e #'hsh))]
50+
#:when (hash? datum)
51+
#:with [(k . v:qqed) ...] (hash->list datum)
52+
#:with ctor (cond [(hash-eq? datum) #'make-immutable-hasheq]
53+
[(hash-eqv? datum) #'make-immutable-hasheqv]
54+
[else #'make-immutable-hash])
55+
#'(ctor (list (pair 'k v.expr) ...))]
56+
[(_ other)
57+
#''other])
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#lang racket/base
2+
3+
(require data/collection/experimental/quasi
4+
racket/stream
5+
rackunit)
6+
7+
(test-case
8+
"Simple successful quasiquotation"
9+
(check-equal? `(1 . #(,(+ 1 1)
10+
#hash((a . #s(sct ,(string-append "a" "b" "c")))
11+
(b . ,(- 4 3)))
12+
4))
13+
'(1 . #(2
14+
#hash((a . #s(sct "abc"))
15+
(b . 1))
16+
4))))
17+
18+
(test-case
19+
"Splicing quasiquotation with sequences"
20+
(check-equal? `(1 ,@(list 2 3 4)
21+
,@(stream 5 6 7)
22+
#hash((a . #s(sct i ,@(vector-immutable 'ii 'iii 'iv) v))))
23+
'(1 2 3 4 5 6 7
24+
#hash((a . #s(sct i ii iii iv v))))))

0 commit comments

Comments
 (0)