racket/collects/scheme/match/parse-quasi.ss
Sam Tobin-Hochstadt ac9d2d8d9e Support prefab struct literals in quasipatterns.
Fixes PR 10050.

svn: r17495
2010-01-06 16:41:17 +00:00

91 lines
3.2 KiB
Scheme

#lang scheme/base
(require (for-template scheme/base)
syntax/boundmap
syntax/stx
scheme/struct-info
"patterns.ss"
"compiler.ss"
"parse-helper.ss")
(provide parse-quasi)
;; is pat a pattern representing a list?
(define (null-terminated? pat)
(cond [(Pair? pat) (null-terminated? (Pair-d pat))]
[(GSeq? pat) (null-terminated? (GSeq-tail pat))]
[(Null? pat) #t]
[else #f]))
;; combine a null-terminated pattern with another pattern to match afterwards
(define (append-pats p1 p2)
(cond [(Pair? p1) (make-Pair (Pair-a p1) (append-pats (Pair-d p1) p2))]
[(GSeq? p1) (make-GSeq (GSeq-headss p1)
(GSeq-mins p1)
(GSeq-maxs p1)
(GSeq-onces? p1)
(append-pats (GSeq-tail p1) p2)
(GSeq-mutable? p1))]
[(Null? p1) p2]
[else (error 'match "illegal input to append-pats")]))
;; parse stx as a quasi-pattern
;; parse/cert parses unquote
(define (parse-quasi stx cert parse/cert)
(define (pq s) (parse-quasi s cert parse/cert))
(syntax-case stx (quasiquote unquote quote unquote-splicing)
[(unquote p) (parse/cert #'p cert)]
[((unquote-splicing p) . rest)
(let ([pat (parse/cert #'p cert)]
[rpat (pq #'rest)])
(if (null-terminated? pat)
(append-pats pat rpat)
(raise-syntax-error 'match "non-list pattern inside unquote-splicing"
stx #'p)))]
[(p dd . rest)
(ddk? #'dd)
(let* ([count (ddk? #'dd)]
[min (and (number? count) count)])
(make-GSeq
(parameterize ([match-...-nesting (add1 (match-...-nesting))])
(list (list (pq #'p))))
(list min)
;; no upper bound
(list #f)
;; patterns in p get bound to lists
(list #f)
(pq #'rest)
#f))]
[(a . b) (make-Pair (pq #'a) (pq #'b))]
;; prefab structs
[struct
(prefab-struct-key (syntax-e #'struct))
(let ([key (prefab-struct-key (syntax-e #'struct))]
[pats (cdr (vector->list (struct->vector (syntax-e #'struct))))])
(make-And (list (make-Pred #`(struct-type-make-predicate (prefab-key->struct-type '#,key #,(length pats))))
(make-App #'struct->vector
(make-Vector (cons (make-Dummy #f) (map pq pats))))))
#;
(make-PrefabStruct key (map pq pats)))]
;; the hard cases
[#(p ...)
(ormap (lambda (p)
(or (ddk? p)
(syntax-case p (unquote-splicing)
[(unquote-splicing . _) #t]
[_ #f])))
(syntax->list #'(p ...)))
(make-And (list (make-Pred #'vector?)
(make-App #'vector->list
(pq (quasisyntax/loc stx (p ...))))))]
[#(p ...)
(make-Vector (map pq (syntax->list #'(p ...))))]
[bx
(box? (syntax-e #'bx))
(make-Box (pq (unbox (syntax-e #'bx))))]
[()
(make-Null (make-Dummy #f))]
[v
(or (parse-literal (syntax-e #'v))
(raise-syntax-error 'match "syntax error in quasipattern" stx))]))