[regexp] checkpoint: added 'define-regexp:'

This commit is contained in:
ben 2015-12-13 00:17:34 -05:00
parent 7a01250dba
commit 1a5dddf009
2 changed files with 104 additions and 37 deletions

View File

@ -3,13 +3,11 @@
;; TODO byte-regexp ;; TODO byte-regexp
(provide (provide
regexp! regexp:
;; (-> String Regexp) define-regexp:
pregexp:
pregexp! regexp-match:
;; (-> String Regexp)
regexp-match!
;; (-> Pattern String Any * (U #f (List String *N+1))) ;; (-> Pattern String Any * (U #f (List String *N+1)))
;; Match the regular expression pattern against a string. ;; Match the regular expression pattern against a string.
;; If the pattern is determined statically, result will be either #f ;; If the pattern is determined statically, result will be either #f
@ -19,54 +17,80 @@
;; Will raise a compile-time exception if the pattern contains unmatched groups. ;; Will raise a compile-time exception if the pattern contains unmatched groups.
) )
(require (require (for-syntax
(for-syntax racket/base syntax/parse racket/syntax)) racket/base
racket/syntax
syntax/id-table
syntax/parse
))
;; ============================================================================= ;; =============================================================================
(define-for-syntax num-groups-key 'num-groups) (define-for-syntax num-groups-key 'regexp-match:num-groups)
(define-for-syntax errloc-key 'regexp-match:)
;; TODO abstract these macros? (define-for-syntax id+num-groups (make-free-id-table))
(define-syntax regexp!
;; (define-matcher f)
;; TODO document
(define-syntax define-matcher
(syntax-parser (syntax-parser
[(_ x:str) [(_ f:id)
(syntax-property #'(regexp x) num-groups-key (count-groups/regexp (syntax-e #'x)))] #:with f: (format-id #'f "~a:" (syntax-e #'f))
[(_ arg* ...) #:with define-f: (format-id #'f "define-~a:" (syntax-e #'f))
#'(regexp arg* ...)])) #'(begin
;; For expressions, (regexp: val)
(define-syntax f:
(syntax-parser
[(_ x:str)
(syntax-property #'(f x)
num-groups-key
(count-groups #'x))]
[(_ arg* (... ...))
#'(f arg* (... ...))]))
;; For definitions, (define-regexp: id val)
(define-syntax define-f:
(syntax-parser
[(_ name:id x)
(free-id-table-set! id+num-groups #'name (count-groups #'x))
#'(define name x)]
[(_ arg* (... ...))
#'(define arg* (... ...))]))) ]))
(define-syntax pregexp! (define-matcher regexp)
(syntax-parser (define-matcher pregexp)
[(_ x:str) (define-matcher byte-regexp)
(syntax-property #'(pregexp x) num-groups-key (count-groups/pregexp (syntax-e #'x)))] (define-matcher byte-pregexp)
[(_ arg* ...)
#'(pregexp arg* ...)]))
(define-syntax regexp-match! (define-syntax regexp-match:
(syntax-parser (syntax-parser
[(f pat-stx arg* ...) [(f pat-stx arg* ...)
#:with num-groups (count-groups #'pat-stx #:src #'f) #:with num-groups (count-groups #'pat-stx)
#:when (syntax-e #'num-groups)
#:with (index* ...) #`#,(for/list ([i (in-range (syntax-e #'num-groups))]) i) #:with (index* ...) #`#,(for/list ([i (in-range (syntax-e #'num-groups))]) i)
#'(let ([maybe-match (regexp-match pat-stx arg* ...)]) #'(let ([maybe-match (regexp-match pat-stx arg* ...)])
(if maybe-match (if maybe-match
(let ([m : (Listof (Option String)) maybe-match]) (let ([m : (Listof (Option String)) maybe-match])
(list (car maybe-match) (list (car maybe-match)
(begin (set! m (cdr m)) (begin (set! m (cdr m))
(or (car m) (error 'regexp-match! (format "Internal error at result index ~a, try Racket's regexp-match" index*)))) (or (car m) (error 'regexp-match: (format "Internal error at result index ~a, try using Racket's regexp-match" index*))))
...)) ...))
#f))] #f))]
[(f arg* ...) [(f arg* ...)
(syntax/loc #'f (regexp-match arg* ...))])) (syntax/loc #'f (regexp-match arg* ...))]))
(define-for-syntax (count-groups v-stx #:src stx) ;; -----------------------------------------------------------------------------
(or (syntax-property v-stx num-groups-key)
(let ([v (format "~a" (syntax-e v-stx))]) (define-for-syntax (count-groups v-stx)
(cond (let ([v (syntax-e v-stx)])
[(string? v) (count-groups/string v #:src stx)] (cond
;[(regexp? v) (count-groups/regexp v #:src stx)] [(identifier? v-stx) (free-id-table-ref id+num-groups v-stx #f)]
;[(pregexp? v) (count-groups/pregexp v #:src stx)] [(string? v) (count-groups/string v #:src v-stx)]
;[(byte-regexp? v) (count-groups/byte-regexp v #:src stx)] [(regexp? v) (count-groups/regexp v #:src v-stx)]
;[(byte-pregexp? v) (count-groups/byte-pregexp v #:src stx)] [(pregexp? v) (count-groups/pregexp v #:src v-stx)]
[else (error 'regexp-match! "Internal error on input" v)])))) [(byte-regexp? v) (count-groups/byte-regexp v #:src v-stx)]
[(byte-pregexp? v) (count-groups/byte-pregexp v #:src v-stx)]
[else (error errloc-key (format "Internal error on input '~e'" v))])))
;; Count the number of matched parentheses in a regexp pattern. ;; Count the number of matched parentheses in a regexp pattern.
;; Raise an exception if there are unmatched parens. ;; Raise an exception if there are unmatched parens.
@ -92,13 +116,19 @@
(loop (+ i 1) in-paren num-groups)])))) (loop (+ i 1) in-paren num-groups)]))))
(define-for-syntax (count-groups/regexp rxp #:src stx) (define-for-syntax (count-groups/regexp rxp #:src stx)
(error 'regexp-match! "Not implemented")) (error errloc-key "Not implemented"))
(define-for-syntax (count-groups/pregexp pxp #:src stx) (define-for-syntax (count-groups/pregexp pxp #:src stx)
(error 'regexp-match! "Not implemented")) (error errloc-key "Not implemented"))
(define-for-syntax (count-groups/byte-regexp rxp #:src stx)
(error errloc-key "Not implemented"))
(define-for-syntax (count-groups/byte-pregexp pxp #:src stx)
(error errloc-key "Not implemented"))
(define-for-syntax (group-error str reason) (define-for-syntax (group-error str reason)
(raise-argument-error (raise-argument-error
'regexp-match! errloc-key
(format "Valid regexp pattern (contains unmatched ~a)" reason) (format "Valid regexp pattern (contains unmatched ~a)" reason)
str)) str))

37
test/regexp/pass.rkt Normal file
View File

@ -0,0 +1,37 @@
#lang typed/racket/base
(require trivial/regexp)
;(: m1 (U #f (List String)))
;(define m1 (regexp-match: "hello" "hello world"))
;
;(: m2 (U #f (List String)))
;(define m2 (regexp-match: "hello" "world"))
;
;(: m3 (U #f (List String String)))
;(define m3 (regexp-match: "he(l*)o" "hellllloooo"))
;
;(: m4 (U #f (List String String String)))
;(define m4 (regexp-match: "he(l*)(o*)" "hellllloooo"))
(: m5 (U #f (List String String String)))
(define m5
(let ()
(define-regexp: rx "he(l*)(o*)")
(regexp-match: rx "helloooooooo")))
;(: m6 (U #f (List String String String)))
;(define m6
; (let ()
; (define-regexp: rx #rx"he(l*)(o*)")
; (regexp-match: rx "helloooooooo")))
;(: m7 (U #f (List String String String)))
;(define m7
; (let ()
; (define-regexp: rx (regexp "he(l*)(o*)"))
; (regexp-match: rx "helloooooooo")))
;(: m6 (U #f (List String String)))
;(define m5 (regexp-match: #rx"he(l*)o" "hellllloooo"))