File: minimatch.rkt

package info (click to toggle)
racket 7.9%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 178,684 kB
  • sloc: ansic: 282,112; lisp: 234,887; pascal: 70,954; sh: 27,112; asm: 16,268; makefile: 4,613; cpp: 2,715; ada: 1,681; javascript: 1,244; cs: 879; exp: 499; csh: 422; python: 274; xml: 106; perl: 104
file content (98 lines) | stat: -rw-r--r-- 3,720 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#lang racket/base
(require (for-syntax racket/base racket/list racket/struct-info))
(provide match match-lambda ?)

(define-syntax (match-lambda stx)
  (syntax-case stx ()
    [(match-lambda clause ...)
     #`(lambda (x)
         (match-c x
           clause ...
           [_ (error 'minimatch-lambda "match at ~s:~s:~s failed: ~e"
                     '#,(syntax-source stx)
                     '#,(syntax-line stx)
                     '#,(syntax-column stx)
                     x)]))]))

(define-syntax (match stx)
  (syntax-case stx ()
    [(match e clause ...)
     #`(let ([x e])
         (match-c x
           clause ...
           [_ (error 'minimatch "match at ~s:~s:~s failed: ~e"
                     '#,(syntax-source stx)
                     '#,(syntax-line stx)
                     '#,(syntax-column stx)
                     x)]))]))

(define-syntax match-c
  (syntax-rules ()
    [(match-c x) (void)]
    [(match-c x [pattern result ...] clause ...)
     (let ([fail (lambda () (match-c x clause ...))])
       (match-p x pattern (let () result ...) (fail)))]))

;; (match-p id Pattern SuccessExpr FailureExpr)
(define-syntax (match-p stx)
  (syntax-case stx (quote cons list vector ?)
    [(match-p x wildcard success failure)
     (and (identifier? #'wildcard) (free-identifier=? #'wildcard #'_))
     #'success]
    [(match-p x (quote lit) success failure)
     #'(if (equal? x (quote lit))
           success
           failure)]
    [(match-p x (cons p1 p2) success failure)
     #'(if (pair? x)
           (let ([x1 (car x)]
                 [x2 (cdr x)])
             (match-p x1 p1 (match-p x2 p2 success failure) failure))
           failure)]
    [(match-p x (list) success failure)
     #'(match-p x (quote ()) success failure)]
    [(match-p x (list p1 p ...) success failure)
     #'(match-p x (cons p1 (list p ...)) success failure)]
    [(match-p x (vector p ...) success failure)
     (with-syntax ([(i ...) (range (length (syntax->list #'(p ...))))])
       #'(if (and (vector? x) (= (vector-length x) (length '(p ...))))
             (match-ep* ([(vector-ref x 'i) p] ...) success failure)
             failure))]
    [(match-p x var success failure)
     (identifier? #'var)
     #'(let ([var x]) success)]
    [(match-p x (? predicate pat ...) success failure)
     #'(if (predicate x)
           (match-ep* ((x pat) ...) success failure)
           failure)]
    [(match-p x (S p ...) success failure)
     (identifier? #'S)
     (let ()
       (define si (syntax-local-value #'S (lambda () #f)))
       (unless (struct-info? si) (raise-syntax-error #f "bad minimatch form" stx #'S))
       (let* ([si (extract-struct-info si)]
              [predicate (list-ref si 2)]
              [accessors (reverse (list-ref si 3))])
         (unless (andmap identifier? accessors)
           (raise-syntax-error #f "struct has incomplete information" #'S))
         (unless (= (length accessors) (length (syntax->list #'(p ...))))
           (raise-syntax-error #f "struct pattern has incorrect number of subpatterns" #'S))
         (with-syntax ([predicate predicate]
                       [(accessor ...) accessors])
           #'(if (predicate x)
                 (match-ep* ([(accessor x) p] ...) success failure)
                 failure))))]
    [(match-p x pattern success failure)
     (raise-syntax-error 'minimatch "bad pattern" #'pattern)]
    ))

(define-syntax match-ep*
  (syntax-rules ()
    [(match-ep* () success failure)
     success]
    [(match-ep* ((e1 p1) . rest) success failure)
     (let ([y e1]) (match-p y p1 (match-ep* rest success failure) failure))]))

(define-syntax ?
  (lambda (stx)
    (raise-syntax-error #f "illegal use of minimatch form '?'" stx)))