#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))]))