91 lines
3.2 KiB
Scheme
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))]))
|