Adjusted rewrite-side-condition/check-errs so that it normalizes the internal
redex patterns a bunch: - repeats are turned into wrappers in sequences, - names are all explicit, - non-terminals are wrapped with `nt', - cross patterns always have the hyphens in them. - ellipses names are normalized (so there are no "hidden" name equalities); this also means that repeat patterns can have both a regular name and a mismatch name Also, added a match-a-pattern helper macro that checks to make sure that functions that process patterns don't miss any cases
This commit is contained in:
parent
c9fcde258f
commit
f1bacffbdc
131
collects/redex/private/match-a-pattern.rkt
Normal file
131
collects/redex/private/match-a-pattern.rkt
Normal file
|
@ -0,0 +1,131 @@
|
|||
#lang racket/base
|
||||
(require racket/match
|
||||
(for-syntax racket/match
|
||||
racket/base))
|
||||
(provide match-a-pattern)
|
||||
|
||||
#|
|
||||
|
||||
The grammar for the internal patterns is the
|
||||
contents of the should-be-pats list, where each
|
||||
'pat' that appears behind an unquote there is
|
||||
a self-reference in the grammar.
|
||||
|
||||
lpat ::= pat
|
||||
| `(repeat ,pat ,(or/c symbol? #f) ,(or/c symbol? #f))
|
||||
;; repeat indicates a repetition (ellipsis in the
|
||||
;; surface language), where the pattern inside is
|
||||
;; what's repeated, the second position is a name
|
||||
;; if the ellipsis is named normally and the final
|
||||
;; position is a name if the ellipsis has a mismatch
|
||||
;; name (more below).
|
||||
var ::= symbol?
|
||||
condition ::= (-> bindings? any) ;; any is treated like a boolean
|
||||
|
||||
Also, the `(cross ,nt) pattern alwyas has hypenated non-terminals, ie
|
||||
(cross e) in the source turns into (cross e-e) after translation (which
|
||||
means that the other cross non-terminals, e.g. (cross e-v), are not
|
||||
directly available as redex patterns, but can only be used via the
|
||||
non-terminals that Redex creates for the cross languages.
|
||||
|
||||
Internal patterns also come with the invariant that there are no
|
||||
redundant or non-local ellipses names. That is, consider this pattern:
|
||||
|
||||
(any_1 ..._1 any_1 ..._2)
|
||||
|
||||
It might seem like it would turn into something like this:
|
||||
|
||||
(list (repeat (name any_1 any) ..._1 #f)
|
||||
(repeat (name any_1 any) ..._2 #f))
|
||||
|
||||
but the _1 and _2 are actually not right, since the x_1 name
|
||||
will force the two ellipses lengths to be the same. So, this
|
||||
must turn into this pattern:
|
||||
|
||||
(list (repeat (name any_1 any) ..._1 #f)
|
||||
(repeat (name any_1 any) ..._1 #f))
|
||||
|
||||
Similarly, if there are superflous names, they are delete. For
|
||||
example, this source pattern:
|
||||
|
||||
(any_1 ..._1)
|
||||
|
||||
turns into this:
|
||||
|
||||
(list (repeat (name any_1 any) #f #f))
|
||||
|
||||
Also, although there cannot be any patterns at the source level
|
||||
that have both kinds of names, there can be once the ellipses
|
||||
have been resolved. For example, this:
|
||||
|
||||
(any_1 ..._1
|
||||
any_1 ..._!_2
|
||||
any_1 ..._1
|
||||
any_1 ..._!_2)
|
||||
|
||||
turns into this:
|
||||
|
||||
(list (repeat (name any_1 any) ..._1 #f)
|
||||
(repeat (name any_1 any) ..._1 ..._!_2)
|
||||
(repeat (name any_1 any) ..._1 #f)
|
||||
(repeat (name any_1 any) ..._1 ..._!_2))
|
||||
|
||||
|#
|
||||
|
||||
(define-syntax (match-a-pattern stx)
|
||||
(syntax-case stx ()
|
||||
[(_ to-match [pats rhs ...] ...)
|
||||
(let ()
|
||||
(define should-be-pats
|
||||
'(`any
|
||||
`number
|
||||
`string
|
||||
`natural
|
||||
`integer
|
||||
`real
|
||||
`variable
|
||||
`(variable-except ,var ...)
|
||||
`(variable-prefix ,var)
|
||||
`variable-not-otherwise-mentioned
|
||||
`hole
|
||||
`(nt ,var)
|
||||
`(name ,var ,pat)
|
||||
`(mismatch-name ,var ,pat)
|
||||
`(in-hole ,pat ,pat) ;; context, then contractum
|
||||
`(hide-hole ,pat)
|
||||
`(side-condition ,pat ,condition ,srcloc-expr)
|
||||
`(cross ,var)
|
||||
`(list ,lpat ...)
|
||||
(? (compose not pair?)) ;; pattern for literals (numbers, strings, prefabs, etc etc etc)
|
||||
))
|
||||
(for ([pat (in-list (syntax->list #'(pats ...)))])
|
||||
(when (null? should-be-pats)
|
||||
(raise-syntax-error 'match-a-pattern "too many patterns" stx pat))
|
||||
(define should-be (car should-be-pats))
|
||||
(set! should-be-pats (cdr should-be-pats))
|
||||
(define pats-match?
|
||||
(let loop ([pat (syntax->datum pat)]
|
||||
[should-be should-be])
|
||||
(cond
|
||||
[(and (null? pat) (null? should-be)) #t]
|
||||
[(and (pair? pat) (pair? should-be))
|
||||
(cond
|
||||
[(eq? (car should-be) 'unquote)
|
||||
(eq? (car pat) 'unquote)]
|
||||
[else
|
||||
(and (loop (car pat) (car should-be))
|
||||
(loop (cdr pat) (cdr should-be)))])]
|
||||
[else (equal? pat should-be)])))
|
||||
(unless pats-match?
|
||||
(raise-syntax-error 'match-a-pattern
|
||||
(format "expected pattern ~s"
|
||||
should-be)
|
||||
stx
|
||||
pat)))
|
||||
(unless (null? should-be-pats)
|
||||
(raise-syntax-error 'match-a-pattern
|
||||
(format "did not find pattern ~s"
|
||||
(car should-be-pats))
|
||||
stx))
|
||||
#'(match to-match [pats rhs ...] ...))]))
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -52,12 +52,7 @@
|
|||
(unless (identifier? #'lang)
|
||||
(raise-syntax-error (syntax-e #'form-name) "expected an identifier in the language position" orig-stx #'lang))
|
||||
(let ([lang-nts (language-id-nts #'lang (syntax-e #'form-name))])
|
||||
(with-syntax ([(((names ...) (names/ellipses ...)) ...)
|
||||
(map (λ (x) (call-with-values
|
||||
(λ () (extract-names lang-nts (syntax-e #'form-name) #t x))
|
||||
list))
|
||||
(syntax->list (syntax (pattern ...))))]
|
||||
[(side-conditions-rewritten ...)
|
||||
(with-syntax ([((side-conditions-rewritten (names ...) (names/ellipses ...)) ...)
|
||||
(map (λ (x) (rewrite-side-conditions/check-errs lang-nts (syntax-e #'form-name) #t x))
|
||||
(syntax->list (syntax (pattern ...))))]
|
||||
[(cp-x ...) (generate-temporaries #'(pattern ...))]
|
||||
|
@ -158,7 +153,7 @@
|
|||
(syntax-case stx ()
|
||||
[(_ red lang nt)
|
||||
(identifier? (syntax nt))
|
||||
(with-syntax ([side-conditions-rewritten
|
||||
(with-syntax ([(side-conditions-rewritten (names ...) (names/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs (language-id-nts #'lang 'compatible-closure)
|
||||
'compatible-closure
|
||||
#t
|
||||
|
@ -170,7 +165,7 @@
|
|||
(define-syntax (context-closure stx)
|
||||
(syntax-case stx ()
|
||||
[(_ red lang pattern)
|
||||
(with-syntax ([side-conditions-rewritten
|
||||
(with-syntax ([(side-conditions-rewritten (names ...) (names/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs (language-id-nts #'lang 'context-closure)
|
||||
'context-closure
|
||||
#t
|
||||
|
@ -291,8 +286,8 @@
|
|||
(syntax-case stx ()
|
||||
[(s (... ...))
|
||||
(let ([r (id/depth #'s)])
|
||||
(make-id/depth (id/depth-id r) (add1 (id/depth-depth r))))]
|
||||
[s (make-id/depth #'s 0)]))
|
||||
(make-id/depth (id/depth-id r) (add1 (id/depth-depth r)) (id/depth-mismatch? r)))]
|
||||
[s (make-id/depth #'s 0 #f)]))
|
||||
(define temporaries (generate-temporaries names))
|
||||
(values
|
||||
(for/fold ([cs '()])
|
||||
|
@ -332,37 +327,33 @@
|
|||
[() body]
|
||||
[((-where x e) y ...)
|
||||
(where-keyword? #'-where)
|
||||
(let-values ([(names names/ellipses) (extract-names lang-nts 'reduction-relation #t #'x)])
|
||||
(define-values (binding-constraints temporaries env+)
|
||||
(generate-binding-constraints names names/ellipses env orig-name))
|
||||
(with-syntax ([(binding-constraints ...) binding-constraints]
|
||||
[side-conditions-rewritten (rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
'reduction-relation
|
||||
#f
|
||||
#'x)]
|
||||
[(names ...) names]
|
||||
[(names/ellipses ...) names/ellipses]
|
||||
[(x ...) temporaries])
|
||||
(let ([rest-body (loop #'(y ...) #`(list x ... #,to-not-be-in) env+)])
|
||||
#`(let* ([mtchs (match-pattern (compile-pattern #,lang `side-conditions-rewritten #t) (term e))]
|
||||
[result (λ (mtch)
|
||||
(let ([bindings (mtch-bindings mtch)])
|
||||
(let ([x (lookup-binding bindings 'names)] ...)
|
||||
(and binding-constraints ...
|
||||
(term-let ([names/ellipses x] ...)
|
||||
#,rest-body)))))])
|
||||
(if mtchs
|
||||
#,
|
||||
(case where-mode
|
||||
[(flatten)
|
||||
#`(for/fold ([r '()]) ([m mtchs])
|
||||
(let ([s (result m)])
|
||||
(if s (append s r) r)))]
|
||||
[(predicate)
|
||||
#`(ormap result mtchs)]
|
||||
[else (error 'unknown-where-mode "~s" where-mode)])
|
||||
#f)))))]
|
||||
(let ()
|
||||
(with-syntax ([(side-conditions-rewritten (names ...) (names/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
'reduction-relation
|
||||
#t
|
||||
#'x)])
|
||||
(define-values (binding-constraints temporaries env+)
|
||||
(generate-binding-constraints (syntax->list #'(names ...))
|
||||
(syntax->list #'(names/ellipses ...))
|
||||
env
|
||||
orig-name))
|
||||
(with-syntax ([(binding-constraints ...) binding-constraints]
|
||||
[(x ...) temporaries])
|
||||
(define rest-body (loop #'(y ...) #`(list x ... #,to-not-be-in) env+))
|
||||
#`(#,(case where-mode
|
||||
[(flatten)
|
||||
#'combine-where-results/flatten]
|
||||
[(predicate)
|
||||
#'combine-where-results/predicate]
|
||||
[else (error 'unknown-where-mode "~s" where-mode)])
|
||||
(match-pattern (compile-pattern #,lang `side-conditions-rewritten #t) (term e))
|
||||
(λ (bindings)
|
||||
(let ([x (lookup-binding bindings 'names)] ...)
|
||||
(and binding-constraints ...
|
||||
(term-let ([names/ellipses x] ...)
|
||||
#,rest-body))))))))]
|
||||
[((-side-condition s ...) y ...)
|
||||
(or (free-identifier=? #'-side-condition #'side-condition)
|
||||
(free-identifier=? #'-side-condition #'side-condition/hidden))
|
||||
|
@ -410,10 +401,12 @@
|
|||
(let ([ellipsis (syntax/loc premise (... ...))])
|
||||
(values #`(#,in #,ellipsis) #`(#,out #,ellipsis)))
|
||||
(values in out)))]
|
||||
[(output-pattern)
|
||||
(rewrite-side-conditions/check-errs lang-nts orig-name #t output-pre-pattern)]
|
||||
[(output-names output-names/ellipses)
|
||||
(extract-names lang-nts orig-name #t output-pre-pattern)]
|
||||
[(output-pattern output-names output-names/ellipses)
|
||||
(with-syntax ([(output names names/ellipses)
|
||||
(rewrite-side-conditions/check-errs lang-nts orig-name #t output-pre-pattern)])
|
||||
(values #'output
|
||||
(syntax->list #'names)
|
||||
(syntax->list #'names/ellipses)))]
|
||||
[(binding-constraints temporaries env+)
|
||||
(generate-binding-constraints output-names output-names/ellipses env orig-name)]
|
||||
[(rest-body) (loop rest-clauses #`(list judgment-output #,to-not-be-in) env+)]
|
||||
|
@ -446,6 +439,17 @@
|
|||
outputs)))
|
||||
outputs)))))]))))
|
||||
|
||||
(define (combine-where-results/flatten mtchs result)
|
||||
(and mtchs
|
||||
(for/fold ([r '()]) ([m mtchs])
|
||||
(let ([s (result (mtch-bindings m))])
|
||||
(if s (append s r) r)))))
|
||||
|
||||
(define (combine-where-results/predicate mtchs result)
|
||||
(and mtchs
|
||||
(for/or ([mtch mtchs])
|
||||
(result (mtch-bindings mtch)))))
|
||||
|
||||
(define (repeated-premise-outputs inputs premise)
|
||||
(if (null? inputs)
|
||||
'(())
|
||||
|
@ -815,7 +819,7 @@
|
|||
(map car (sort (hash-map name-table (λ (k v) (list k (list-ref v 1)))) < #:key cadr)))]
|
||||
[lws lws]
|
||||
|
||||
[domain-pattern-side-conditions-rewritten
|
||||
[(domain-pattern-side-conditions-rewritten (names ...) (names/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
orig-name
|
||||
|
@ -868,31 +872,30 @@
|
|||
(let* ([lang-nts (language-id-nts lang-id orig-name)]
|
||||
[rewrite-side-conds
|
||||
(λ (pat) (rewrite-side-conditions/check-errs lang-nts orig-name #t pat))])
|
||||
(let-values ([(names names/ellipses) (extract-names lang-nts orig-name #t (syntax rhs-from))])
|
||||
(with-syntax ([(names ...) names]
|
||||
[(names/ellipses ...) names/ellipses]
|
||||
[side-conditions-rewritten (rewrite-side-conds
|
||||
(rewrite-node-pat (syntax-e (syntax lhs-frm-id))
|
||||
(syntax rhs-from)))]
|
||||
[fresh-rhs-from (rewrite-side-conds
|
||||
(freshen-names #'rhs-from #'lhs-frm-id lang-nts orig-name))]
|
||||
[lang lang])
|
||||
(map
|
||||
(λ (child-proc)
|
||||
#`(do-node-match
|
||||
'lhs-frm-id
|
||||
'lhs-to-id
|
||||
`side-conditions-rewritten
|
||||
(λ (bindings rhs-binder)
|
||||
(term-let ([lhs-to-id rhs-binder]
|
||||
[names/ellipses (lookup-binding bindings 'names)] ...)
|
||||
(term rhs-to)))
|
||||
#,child-proc
|
||||
`fresh-rhs-from))
|
||||
(get-choices stx orig-name bm #'lang
|
||||
(syntax lhs-arrow)
|
||||
name-table lang-id
|
||||
allow-zero-rules?)))))]))
|
||||
(with-syntax ([(side-conditions-rewritten (names ...) (names/ellipses ...))
|
||||
(rewrite-side-conds
|
||||
(rewrite-node-pat (syntax-e (syntax lhs-frm-id))
|
||||
(syntax rhs-from)))]
|
||||
[(fresh-rhs-from (fresh-names ...) (fresh-names/ellipses ...))
|
||||
(rewrite-side-conds
|
||||
(freshen-names #'rhs-from #'lhs-frm-id lang-nts orig-name))]
|
||||
[lang lang])
|
||||
(map
|
||||
(λ (child-proc)
|
||||
#`(do-node-match
|
||||
'lhs-frm-id
|
||||
'lhs-to-id
|
||||
`side-conditions-rewritten
|
||||
(λ (bindings rhs-binder)
|
||||
(term-let ([lhs-to-id rhs-binder]
|
||||
[names/ellipses (lookup-binding bindings 'names)] ...)
|
||||
(term rhs-to)))
|
||||
#,child-proc
|
||||
`fresh-rhs-from))
|
||||
(get-choices stx orig-name bm #'lang
|
||||
(syntax lhs-arrow)
|
||||
name-table lang-id
|
||||
allow-zero-rules?))))]))
|
||||
(define (rewrite-node-pat id term)
|
||||
(let loop ([t term])
|
||||
(syntax-case t (side-condition)
|
||||
|
@ -936,37 +939,37 @@
|
|||
(let* ([lang-nts (language-id-nts lang-id orig-name)]
|
||||
[rw-sc (λ (pat) (rewrite-side-conditions/check-errs lang-nts orig-name #t pat))])
|
||||
(let-values ([(name computed-name sides/withs/freshs) (process-extras stx orig-name name-table extras)])
|
||||
(let*-values ([(names names/ellipses) (extract-names lang-nts orig-name #t from)]
|
||||
[(body-code)
|
||||
(bind-withs orig-name
|
||||
#'main-exp
|
||||
lang
|
||||
lang-nts
|
||||
sides/withs/freshs
|
||||
'flatten
|
||||
#`(list (cons #,(or computed-name #'none)
|
||||
(term #,to)))
|
||||
names names/ellipses)]
|
||||
[(test-case-body-code)
|
||||
;; this contains some redundant code
|
||||
(bind-withs orig-name
|
||||
#'#t
|
||||
#'lang-id2
|
||||
lang-nts
|
||||
sides/withs/freshs
|
||||
'predicate
|
||||
#'#t
|
||||
names names/ellipses)])
|
||||
(with-syntax ([side-conditions-rewritten (rw-sc from)]
|
||||
[lhs-w/extras (rw-sc #`(side-condition #,from #,test-case-body-code))]
|
||||
(with-syntax ([(side-conditions-rewritten (names ...) (names/ellipses ...)) (rw-sc from)])
|
||||
(define body-code
|
||||
(bind-withs orig-name
|
||||
#'main-exp
|
||||
lang
|
||||
lang-nts
|
||||
sides/withs/freshs
|
||||
'flatten
|
||||
#`(list (cons #,(or computed-name #'none)
|
||||
(term #,to)))
|
||||
(syntax->list #'(names ...))
|
||||
(syntax->list #'(names/ellipses ...))))
|
||||
(define test-case-body-code
|
||||
;; this contains some redundant code
|
||||
(bind-withs orig-name
|
||||
#'#t
|
||||
#'lang-id2
|
||||
lang-nts
|
||||
sides/withs/freshs
|
||||
'predicate
|
||||
#'#t
|
||||
(syntax->list #'(names ...))
|
||||
(syntax->list #'(names/ellipses ...))))
|
||||
(with-syntax ([(lhs-w/extras (w/extras-names ...) (w/extras-names/ellipses ...))
|
||||
(rw-sc #`(side-condition #,from #,test-case-body-code))]
|
||||
[lhs-source (format "~a:~a:~a"
|
||||
(syntax-source from)
|
||||
(syntax-line from)
|
||||
(syntax-column from))]
|
||||
[name name]
|
||||
[lang lang]
|
||||
[(names ...) names]
|
||||
[(names/ellipses ...) names/ellipses]
|
||||
[body-code body-code])
|
||||
#`
|
||||
(build-rewrite-proc/leaf `side-conditions-rewritten
|
||||
|
@ -1263,13 +1266,13 @@
|
|||
[(form-name lang-exp pattern)
|
||||
(identifier? #'lang-exp)
|
||||
(let*-values ([(what) (syntax-e #'form-name)]
|
||||
[(nts) (language-id-nts #'lang-exp what)]
|
||||
[(ids/depths _) (extract-names nts what #t #'pattern)])
|
||||
(with-syntax ([side-condition-rewritten (rewrite-side-conditions/check-errs nts what #t #'pattern)]
|
||||
[binders (map syntax-e ids/depths)]
|
||||
[name (syntax-local-infer-name stx)])
|
||||
(syntax
|
||||
(do-test-match lang-exp `side-condition-rewritten 'binders 'name))))]
|
||||
[(nts) (language-id-nts #'lang-exp what)])
|
||||
(with-syntax ([(side-condition-rewritten (vars ...) (ids/depths ...))
|
||||
(rewrite-side-conditions/check-errs nts what #t #'pattern)])
|
||||
(with-syntax ([binders (map syntax-e (syntax->list #'(ids/depths ...)))]
|
||||
[name (syntax-local-infer-name stx)])
|
||||
(syntax
|
||||
(do-test-match lang-exp `side-condition-rewritten 'binders 'name)))))]
|
||||
[(form-name lang-exp pattern expression)
|
||||
(identifier? #'lang-exp)
|
||||
(syntax
|
||||
|
@ -1464,7 +1467,7 @@
|
|||
[codom-contracts (syntax-e #'codom-contracts)]
|
||||
[pats (syntax-e #'pats)]
|
||||
[relation? (syntax-e #'relation?)]
|
||||
[syn-error-name (syntax-e #'syn-err-name)])
|
||||
[syn-error-name (syntax-e #'syn-error-name)])
|
||||
(define lang-nts
|
||||
(definition-nts #'lang #'orig-stx syn-error-name))
|
||||
(with-syntax ([(((original-names lhs-clauses ...) raw-rhses ...) ...) pats]
|
||||
|
@ -1477,8 +1480,13 @@
|
|||
#'((raw-rhses ...) ...))]
|
||||
[(lhs ...) #'((lhs-clauses ...) ...)])
|
||||
(parse-extras #'((stuff ...) ...))
|
||||
(let-values ([(lhs-namess lhs-namess/ellipsess)
|
||||
(lhss-bound-names (syntax->list (syntax (lhs ...))) lang-nts syn-error-name)])
|
||||
(with-syntax ([((side-conditions-rewritten lhs-names lhs-namess/ellipses) ...)
|
||||
(map (λ (x) (rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
syn-error-name
|
||||
#t
|
||||
x))
|
||||
(syntax->list (syntax (lhs ...))))])
|
||||
(with-syntax ([(rhs/wheres ...)
|
||||
(map (λ (sc/b rhs names names/ellipses)
|
||||
(bind-withs
|
||||
|
@ -1486,10 +1494,12 @@
|
|||
#'effective-lang lang-nts
|
||||
sc/b 'flatten
|
||||
#`(list (term #,rhs))
|
||||
names names/ellipses))
|
||||
(syntax->list names)
|
||||
(syntax->list names/ellipses)))
|
||||
(syntax->list #'((stuff ...) ...))
|
||||
(syntax->list #'(rhs ...))
|
||||
lhs-namess lhs-namess/ellipsess)]
|
||||
(syntax->list #'(lhs-names ...))
|
||||
(syntax->list #'(lhs-namess/ellipses ...)))]
|
||||
[(rg-rhs/wheres ...)
|
||||
(map (λ (sc/b rhs names names/ellipses)
|
||||
(bind-withs
|
||||
|
@ -1497,18 +1507,13 @@
|
|||
#'effective-lang lang-nts
|
||||
sc/b 'predicate
|
||||
#`#t
|
||||
names names/ellipses))
|
||||
(syntax->list names)
|
||||
(syntax->list names/ellipses)))
|
||||
(syntax->list #'((stuff ...) ...))
|
||||
(syntax->list #'(rhs ...))
|
||||
lhs-namess lhs-namess/ellipsess)])
|
||||
(with-syntax ([(side-conditions-rewritten ...)
|
||||
(map (λ (x) (rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
syn-error-name
|
||||
#t
|
||||
x))
|
||||
(syntax->list (syntax (lhs ...))))]
|
||||
[(rg-side-conditions-rewritten ...)
|
||||
(syntax->list #'(lhs-names ...))
|
||||
(syntax->list #'(lhs-namess/ellipses ...)))])
|
||||
(with-syntax ([((rg-side-conditions-rewritten rg-names rg-names/ellipses ...) ...)
|
||||
(map (λ (x) (rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
syn-error-name
|
||||
|
@ -1522,14 +1527,15 @@
|
|||
(syntax-line lhs)
|
||||
(syntax-column lhs)))
|
||||
pats)]
|
||||
[dom-side-conditions-rewritten
|
||||
(and dom-ctcs
|
||||
(rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
syn-error-name
|
||||
#f
|
||||
dom-ctcs))]
|
||||
[(codom-side-conditions-rewritten ...)
|
||||
[(dom-side-conditions-rewritten dom-names dom-names/ellipses)
|
||||
(if dom-ctcs
|
||||
(rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
syn-error-name
|
||||
#f
|
||||
dom-ctcs)
|
||||
#'(any () ()))]
|
||||
[((codom-side-conditions-rewritten codom-names codom-names/ellipses) ...)
|
||||
(map (λ (codom-contract)
|
||||
(rewrite-side-conditions/check-errs
|
||||
lang-nts
|
||||
|
@ -1547,7 +1553,8 @@
|
|||
(term-let-fn ((name name))
|
||||
(term-let ([names/ellipses (lookup-binding bindings 'names)] ...)
|
||||
rhs/where))))))
|
||||
lhs-namess lhs-namess/ellipsess
|
||||
(syntax->list #'(lhs-names ...))
|
||||
(syntax->list #'(lhs-namess/ellipses ...))
|
||||
(syntax->list (syntax (rhs/wheres ...))))])
|
||||
(syntax-property
|
||||
(prune-syntax
|
||||
|
@ -1587,7 +1594,7 @@
|
|||
dsc
|
||||
(append cases parent-cases)
|
||||
#,relation?))
|
||||
dsc
|
||||
#,(if dom-ctcs #'dsc #f)
|
||||
`(codom-side-conditions-rewritten ...)
|
||||
'name
|
||||
#,relation?))))
|
||||
|
@ -1680,17 +1687,6 @@
|
|||
(raise-syntax-error
|
||||
#f "mode and contract specify different numbers of positions" full-def)))
|
||||
|
||||
(define-for-syntax (lhss-bound-names lhss nts syn-error-name)
|
||||
(let loop ([lhss lhss])
|
||||
(if (null? lhss)
|
||||
(values null null)
|
||||
(let-values ([(namess namess/ellipsess)
|
||||
(loop (cdr lhss))]
|
||||
[(names names/ellipses)
|
||||
(extract-names nts syn-error-name #t (car lhss))])
|
||||
(values (cons names namess)
|
||||
(cons names/ellipses namess/ellipsess))))))
|
||||
|
||||
(define-for-syntax (defined-name declared-names clauses orig-stx)
|
||||
(with-syntax ([(((used-names _ ...) _ ...) ...) clauses])
|
||||
(define-values (the-name other-names)
|
||||
|
@ -1892,26 +1888,30 @@
|
|||
(syntax-case clause ()
|
||||
[((_ . conc-pats) . prems)
|
||||
(let-values ([(input-pats output-pats) (split-by-mode (syntax->list #'conc-pats) mode)])
|
||||
(define-values (input-names input-names/ellipses)
|
||||
(extract-names nts syn-error-name #t input-pats))
|
||||
(define ((rewrite-pattern binds?) pat)
|
||||
(rewrite-side-conditions/check-errs nts syn-error-name binds? pat))
|
||||
(define (contracts-compilation ctcs)
|
||||
(and ctcs #`(map (λ (p) (compile-pattern #,lang p #f)) `#,ctcs)))
|
||||
(define-values (input-contracts output-contracts)
|
||||
(syntax-case contracts ()
|
||||
[#f (values #f #f)]
|
||||
[(p ...)
|
||||
(let-values ([(ins outs) (split-by-mode (syntax->list #'(p ...)) mode)])
|
||||
(values (map (rewrite-pattern #f) ins)
|
||||
(map (rewrite-pattern #f) outs)))]))
|
||||
(define lhs (map (rewrite-pattern #t) input-pats))
|
||||
(define body
|
||||
(bind-withs syn-error-name '() lang nts (syntax->list #'prems)
|
||||
'flatten #`(list (term (#,@output-pats))) input-names input-names/ellipses))
|
||||
(with-syntax ([(names ...) input-names]
|
||||
[(names/ellipses ...) input-names/ellipses])
|
||||
#`(let ([compiled-lhs (compile-pattern #,lang `#,lhs #t)]
|
||||
(with-syntax ([(lhs (names ...) (names/ellipses ...)) ((rewrite-pattern #t) input-pats)])
|
||||
(define (contracts-compilation ctcs)
|
||||
(and ctcs
|
||||
(with-syntax ([(ctc ...) ctcs])
|
||||
#`(list (compile-pattern #,lang `ctc #f) ...))))
|
||||
(define-values (input-contracts output-contracts)
|
||||
(syntax-case contracts ()
|
||||
[#f (values #f #f)]
|
||||
[(p ...)
|
||||
(let-values ([(ins outs) (split-by-mode (syntax->list #'(p ...)) mode)])
|
||||
(with-syntax ([((in-pat in-names in-names/ellipses) ...)
|
||||
(map (rewrite-pattern #f) ins)]
|
||||
[((out-pat out-names out-names/ellipses) ...)
|
||||
(map (rewrite-pattern #f) outs)])
|
||||
(values #'(in-pat ...)
|
||||
#'(out-pat ...))))]))
|
||||
(define body
|
||||
(bind-withs syn-error-name '() lang nts (syntax->list #'prems)
|
||||
'flatten #`(list (term (#,@output-pats)))
|
||||
(syntax->list #'(names ...))
|
||||
(syntax->list #'(names/ellipses ...))))
|
||||
#`(let ([compiled-lhs (compile-pattern #,lang `lhs #t)]
|
||||
[compiled-input-ctcs #,(contracts-compilation input-contracts)]
|
||||
[compiled-output-ctcs #,(contracts-compilation output-contracts)])
|
||||
(λ (input)
|
||||
|
@ -2392,7 +2392,7 @@
|
|||
(prune-syntax
|
||||
(let ()
|
||||
(let ([all-names (syntax->list #'(all-names ...))])
|
||||
(with-syntax ([((r-rhs ...) ...)
|
||||
(with-syntax ([(((r-rhs r-names r-names/ellipses) ...) ...)
|
||||
(map (lambda (rhss)
|
||||
(map (lambda (rhs)
|
||||
(rewrite-side-conditions/check-errs
|
||||
|
@ -2450,7 +2450,7 @@
|
|||
(begin (void) refs ...))
|
||||
(compile-language (list (list '(uniform-names ...) rhs/lw ...) ...)
|
||||
(list (make-nt 'first-names (list (make-rhs `r-rhs) ...)) ...
|
||||
(make-nt 'new-name (list (make-rhs 'orig-name))) ...)
|
||||
(make-nt 'new-name (list (make-rhs '(nt orig-name)))) ...)
|
||||
'((uniform-names ...) ...)))))))))]))
|
||||
|
||||
(define-syntax (define-extended-language stx)
|
||||
|
@ -2483,31 +2483,21 @@
|
|||
(define-syntax (extend-language stx)
|
||||
(syntax-case stx ()
|
||||
[(_ lang (all-names ...) (name rhs ...) ...)
|
||||
(with-syntax ([((r-rhs ...) ...) (map (lambda (rhss) (map (λ (x) (rewrite-side-conditions/check-errs
|
||||
(append (language-id-nts #'lang 'define-extended-language)
|
||||
(map syntax-e
|
||||
(syntax->list #'(all-names ...))))
|
||||
'define-extended-language
|
||||
#f
|
||||
x))
|
||||
(syntax->list rhss)))
|
||||
(syntax->list (syntax ((rhs ...) ...))))]
|
||||
(with-syntax ([(((r-rhs r-names r-names/ellipses) ...) ...)
|
||||
(map (lambda (rhss) (map (λ (x) (rewrite-side-conditions/check-errs
|
||||
(append (language-id-nts #'lang 'define-extended-language)
|
||||
(map syntax-e
|
||||
(syntax->list #'(all-names ...))))
|
||||
'define-extended-language
|
||||
#f
|
||||
x))
|
||||
(syntax->list rhss)))
|
||||
(syntax->list (syntax ((rhs ...) ...))))]
|
||||
[((rhs/lw ...) ...) (map (lambda (rhss) (map to-lw/proc (syntax->list rhss)))
|
||||
(syntax->list (syntax ((rhs ...) ...))))]
|
||||
[((uniform-names ...) ...)
|
||||
(map (λ (x) (if (identifier? x) (list x) x))
|
||||
(syntax->list (syntax (name ...))))]
|
||||
|
||||
[((new-name orig-name) ...)
|
||||
(apply
|
||||
append
|
||||
(map (λ (name-stx)
|
||||
(if (identifier? name-stx)
|
||||
'()
|
||||
(let ([l (syntax->list name-stx)])
|
||||
(map (λ (x) (list x (car l)))
|
||||
(cdr l)))))
|
||||
(syntax->list #'(name ...))))])
|
||||
(syntax->list (syntax (name ...))))])
|
||||
(syntax/loc stx
|
||||
(do-extend-language lang
|
||||
(list (make-nt '(uniform-names ...) (list (make-rhs `r-rhs) ...)) ...)
|
||||
|
@ -2587,7 +2577,7 @@
|
|||
(for-each (λ (shortcut-name)
|
||||
(hash-set! new-ht
|
||||
shortcut-name
|
||||
(make-nt shortcut-name (list (make-rhs (car names))))))
|
||||
(make-nt shortcut-name (list (make-rhs `(nt ,(car names)))))))
|
||||
(cdr names)))))
|
||||
|
||||
new-nts)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
(module rewrite-side-conditions scheme
|
||||
#lang racket/base
|
||||
|
||||
(require mzlib/list
|
||||
"underscore-allowed.rkt")
|
||||
(require (for-template
|
||||
(require "term.rkt"
|
||||
(for-template
|
||||
mzscheme
|
||||
"term.rkt"
|
||||
"matcher.rkt"))
|
||||
|
@ -36,91 +38,310 @@
|
|||
stx))
|
||||
(define (expected-arguments name stx)
|
||||
(raise-syntax-error what (format "~a expected to have arguments" name) orig-stx stx))
|
||||
(define ((expect-identifier src) stx)
|
||||
(define (expect-identifier src stx)
|
||||
(unless (identifier? stx)
|
||||
(raise-syntax-error what "expected an identifier" src stx)))
|
||||
|
||||
;; call this and discard the result to ensure that all names are at the right ellipsis depths.
|
||||
(extract-names all-nts what bind-names? orig-stx)
|
||||
; union-find w/o balancing or path compression (at least for now)
|
||||
(define (union e f sets)
|
||||
(hash-set sets (find f sets) (find e sets)))
|
||||
(define (find e sets)
|
||||
(let recur ([chd e] [par (hash-ref sets e #f)])
|
||||
(if (and par (not (eq? chd par))) (recur par (hash-ref sets par #f)) chd)))
|
||||
|
||||
(let loop ([term orig-stx])
|
||||
(syntax-case term (side-condition variable-except variable-prefix hole name in-hole hide-hole cross unquote and)
|
||||
[(side-condition pre-pat (and))
|
||||
;; rewriting metafunctions (and possibly other things) that have no where, etc clauses
|
||||
;; end up with side-conditions that are empty 'and' expressions, so we just toss them here.
|
||||
(loop #'pre-pat)]
|
||||
[(side-condition pre-pat exp)
|
||||
(with-syntax ([pat (loop (syntax pre-pat))])
|
||||
(let-values ([(names names/ellipses) (extract-names all-nts what bind-names? (syntax pat))])
|
||||
(with-syntax ([(name ...) names]
|
||||
[(name/ellipses ...) names/ellipses]
|
||||
(define last-contexts (make-hasheq))
|
||||
(define assignments #hasheq())
|
||||
(define (record-binder pat-stx under)
|
||||
(define pat-sym (syntax->datum pat-stx))
|
||||
(set! assignments
|
||||
(if (null? under)
|
||||
assignments
|
||||
(let ([last (hash-ref last-contexts pat-sym #f)])
|
||||
(if last
|
||||
(foldl (λ (cur last asgns) (union cur last asgns)) assignments under last)
|
||||
(begin
|
||||
(hash-set! last-contexts pat-sym under)
|
||||
assignments))))))
|
||||
|
||||
(define ellipsis-number 0)
|
||||
|
||||
(define-values (term names)
|
||||
(let loop ([term orig-stx]
|
||||
[under '()])
|
||||
(syntax-case term (side-condition variable-except variable-prefix hole name in-hole hide-hole cross unquote and)
|
||||
[(side-condition pre-pat (and))
|
||||
;; rewriting metafunctions (and possibly other things) that have no where, etc clauses
|
||||
;; end up with side-conditions that are empty 'and' expressions, so we just toss them here.
|
||||
(loop #'pre-pat under)]
|
||||
[(side-condition pre-pat exp)
|
||||
(let ()
|
||||
(define-values (pre-term pre-vars) (loop #'pre-pat under))
|
||||
(define names/ellipses (map build-dots pre-vars))
|
||||
(with-syntax ([pre-term pre-term]
|
||||
[((name name/ellipses) ...)
|
||||
(filter
|
||||
values
|
||||
(map (λ (id name/ellipses)
|
||||
(if (id/depth-mismatch? id)
|
||||
#f
|
||||
(list (id/depth-id id)
|
||||
name/ellipses)))
|
||||
pre-vars
|
||||
names/ellipses))]
|
||||
[src-loc (parameterize ([print-syntax-width 0])
|
||||
(format "~s" #'exp))])
|
||||
(syntax/loc term
|
||||
(side-condition
|
||||
pat
|
||||
,(lambda (bindings)
|
||||
(term-let
|
||||
([name/ellipses (lookup-binding bindings 'name)] ...)
|
||||
exp))
|
||||
; For use in error messages.
|
||||
src-loc)))))]
|
||||
[(side-condition a ...) (expected-exact 'side-condition 2 term)]
|
||||
[side-condition (expected-arguments 'side-condition term)]
|
||||
[(variable-except a ...)
|
||||
(for-each (expect-identifier term) (syntax->list #'(a ...)))
|
||||
term]
|
||||
[variable-except (expected-arguments 'variable-except term)]
|
||||
[(variable-prefix a)
|
||||
((expect-identifier term) #'a)
|
||||
term]
|
||||
[(variable-prefix a ...) (expected-exact 'variable-prefix 1 term)]
|
||||
[variable-prefix (expected-arguments 'variable-prefix term)]
|
||||
[hole term]
|
||||
[(name x y) #`(name x #,(loop #'y))]
|
||||
[(name x ...) (expected-exact 'name 2 term)]
|
||||
[name (expected-arguments 'name term)]
|
||||
[(in-hole a b) #`(in-hole #,(loop #'a) #,(loop #'b))]
|
||||
[(in-hole a ...) (expected-exact 'in-hole 2 term)]
|
||||
[in-hole (expected-arguments 'in-hole term)]
|
||||
[(hide-hole a) #`(hide-hole #,(loop #'a))]
|
||||
[(hide-hole a ...) (expected-exact 'hide-hole 1 term)]
|
||||
[hide-hole (expected-arguments 'hide-hole term)]
|
||||
[(cross a)
|
||||
((expect-identifier term) #'a)
|
||||
term]
|
||||
[(cross a ...) (expected-exact 'cross 1 term)]
|
||||
[cross (expected-arguments 'cross term)]
|
||||
[(unquote . _)
|
||||
(raise-syntax-error what "unquote disallowed in patterns" orig-stx term)]
|
||||
[_
|
||||
(identifier? term)
|
||||
(match (regexp-match #rx"^([^_]*)_.*" (symbol->string (syntax-e term)))
|
||||
[(list _ (app string->symbol s))
|
||||
(if (or (memq s (cons '... underscore-allowed))
|
||||
(memq s all-nts))
|
||||
term
|
||||
(raise-syntax-error
|
||||
what
|
||||
(format "before underscore must be either a non-terminal or a built-in pattern, found ~a in ~s"
|
||||
s (syntax-e term))
|
||||
orig-stx
|
||||
term))]
|
||||
[_ term])]
|
||||
[(terms ...)
|
||||
(map loop (syntax->list (syntax (terms ...))))]
|
||||
[else
|
||||
(when (pair? (syntax-e term))
|
||||
(let loop ([term term])
|
||||
(values (syntax/loc term
|
||||
(side-condition
|
||||
pre-term
|
||||
,(lambda (bindings)
|
||||
(term-let
|
||||
([name/ellipses (lookup-binding bindings 'name)] ...)
|
||||
exp))
|
||||
; For use in error messages.
|
||||
src-loc))
|
||||
pre-vars)))]
|
||||
[(side-condition a ...) (expected-exact 'side-condition 2 term)]
|
||||
[side-condition (expected-arguments 'side-condition term)]
|
||||
[(variable-except a ...)
|
||||
(begin
|
||||
(for ([a (in-list (syntax->list #'(a ...)))])
|
||||
(expect-identifier term a))
|
||||
(values term '()))]
|
||||
[variable-except (expected-arguments 'variable-except term)]
|
||||
[(variable-prefix a)
|
||||
(begin
|
||||
(expect-identifier term #'a)
|
||||
(values term '()))]
|
||||
[(variable-prefix a ...) (expected-exact 'variable-prefix 1 term)]
|
||||
[variable-prefix (expected-arguments 'variable-prefix term)]
|
||||
[hole (values term '())]
|
||||
[(name x y)
|
||||
(let ()
|
||||
(define-values (sub-term sub-vars) (loop #'y under))
|
||||
(record-binder #'x under)
|
||||
(values #`(name x #,sub-term)
|
||||
(cons (make-id/depth #'x (length under) #f)
|
||||
sub-vars)))]
|
||||
[(name x ...) (expected-exact 'name 2 term)]
|
||||
[name (expected-arguments 'name term)]
|
||||
[(in-hole a b)
|
||||
(let ()
|
||||
(define-values (a-term a-vars) (loop #'a under))
|
||||
(define-values (b-term b-vars) (loop #'b under))
|
||||
(values #`(in-hole #,a-term #,b-term)
|
||||
(append a-vars b-vars)))]
|
||||
[(in-hole a ...) (expected-exact 'in-hole 2 term)]
|
||||
[in-hole (expected-arguments 'in-hole term)]
|
||||
[(hide-hole a)
|
||||
(let ()
|
||||
(define-values (sub-term vars) (loop #'a under))
|
||||
(values #`(hide-hole #,sub-term) vars))]
|
||||
[(hide-hole a ...) (expected-exact 'hide-hole 1 term)]
|
||||
[hide-hole (expected-arguments 'hide-hole term)]
|
||||
[(cross a)
|
||||
(let ()
|
||||
(expect-identifier term #'a)
|
||||
(define a-str (symbol->string (syntax-e #'a)))
|
||||
(values #`(cross #,(string->symbol (format "~a-~a" a-str a-str)))
|
||||
'()))]
|
||||
[(cross a ...) (expected-exact 'cross 1 term)]
|
||||
[cross (expected-arguments 'cross term)]
|
||||
[(unquote . _)
|
||||
(raise-syntax-error what "unquote disallowed in patterns" orig-stx term)]
|
||||
[_
|
||||
(identifier? term)
|
||||
(let ()
|
||||
(define m (regexp-match #rx"^([^_]*)_(.*)$" (symbol->string (syntax-e term))))
|
||||
(cond
|
||||
[(syntax? term) (loop (syntax-e term))]
|
||||
[(pair? term) (loop (cdr term))]
|
||||
[(null? term) (void)]
|
||||
[#t
|
||||
(raise-syntax-error what "dotted pairs not supported in patterns" orig-stx term)])))
|
||||
term])))
|
||||
[m
|
||||
(define prefix (list-ref m 1))
|
||||
(define suffix (list-ref m 2))
|
||||
(define suffix-sym (string->symbol suffix))
|
||||
(define prefix-sym (string->symbol prefix))
|
||||
(define prefix-stx (datum->syntax term prefix-sym))
|
||||
(define mismatch? (regexp-match? #rx"^!_" suffix))
|
||||
(cond
|
||||
[(eq? prefix-sym '...)
|
||||
(raise-syntax-error
|
||||
what
|
||||
"found an ellipsis outside of a sequence"
|
||||
orig-stx
|
||||
term)]
|
||||
[(memq prefix-sym all-nts)
|
||||
(record-binder term under)
|
||||
(values (if mismatch?
|
||||
`(mismatch-name ,term (nt ,prefix-stx))
|
||||
`(name ,term (nt ,prefix-stx)))
|
||||
(list (make-id/depth term (length under) mismatch?)))]
|
||||
[(memq prefix-sym underscore-allowed)
|
||||
(record-binder term under)
|
||||
(values (if mismatch?
|
||||
`(mismatch-name ,term ,prefix-stx)
|
||||
`(name ,term ,prefix-stx))
|
||||
(list (make-id/depth term (length under) mismatch?)))]
|
||||
[else
|
||||
(raise-syntax-error
|
||||
what
|
||||
(format "before underscore must be either a non-terminal or a built-in pattern, found ~a in ~s"
|
||||
suffix-sym (syntax-e term))
|
||||
orig-stx
|
||||
term)])]
|
||||
[(eq? (syntax-e term) '...)
|
||||
(raise-syntax-error
|
||||
what
|
||||
"found an ellipsis outside of a sequence"
|
||||
orig-stx
|
||||
term)]
|
||||
[(memq (syntax-e term) all-nts)
|
||||
(cond
|
||||
[bind-names?
|
||||
(record-binder term under)
|
||||
(values `(name ,term (nt ,term)) (list (make-id/depth term (length under) #f)))]
|
||||
[else
|
||||
(values `(nt ,term) '())])]
|
||||
[(memq (syntax-e term) underscore-allowed)
|
||||
(cond
|
||||
[bind-names?
|
||||
(record-binder #'term under)
|
||||
(values `(name ,term ,term) (list (make-id/depth term (length under) #f)))]
|
||||
[else
|
||||
(values term '())])]
|
||||
[else
|
||||
(values term '())]))]
|
||||
[(terms ...)
|
||||
(let ()
|
||||
(define terms-lst (syntax->list #'(terms ...)))
|
||||
(define (is-ellipsis? term)
|
||||
(and (identifier? term)
|
||||
(regexp-match? #rx"^[.][.][.]" (symbol->string (syntax-e term)))))
|
||||
(when (and (pair? terms-lst) (is-ellipsis? (car terms-lst)))
|
||||
(raise-syntax-error what
|
||||
"ellipsis should not appear in the first position of a sequence"
|
||||
orig-stx
|
||||
term))
|
||||
(define-values (updated-terms vars)
|
||||
(let t-loop ([terms terms-lst])
|
||||
(cond
|
||||
[(null? terms) (values '() '())]
|
||||
[(null? (cdr terms))
|
||||
(define-values (term vars) (loop (car terms) under))
|
||||
(values (list term) vars)]
|
||||
[(is-ellipsis? (cadr terms))
|
||||
(when (and (pair? (cddr terms))
|
||||
(is-ellipsis? (caddr terms)))
|
||||
(raise-syntax-error what
|
||||
"two ellipses should not appear in a row"
|
||||
orig-stx
|
||||
(cadr terms)
|
||||
(list (caddr terms))))
|
||||
(define ellipsis-sym (syntax-e (cadr terms)))
|
||||
(define ellipsis-pre-str (symbol->string ellipsis-sym))
|
||||
(define mismatch? (regexp-match? #rx"^[.][.][.]_!_" ellipsis-pre-str))
|
||||
(define ellipsis-str (cond
|
||||
[mismatch?
|
||||
(set! ellipsis-number (+ ellipsis-number 1))
|
||||
(format "..._r~a" ellipsis-number)]
|
||||
[(regexp-match? #rx"^[.][.][.]_r" ellipsis-pre-str)
|
||||
(string-append (substring ellipsis-str 0 4)
|
||||
"r"
|
||||
(substring ellipsis-str
|
||||
4
|
||||
(string-length ellipsis-str)))]
|
||||
[(regexp-match? #rx"^[.][.][.]_" ellipsis-pre-str)
|
||||
ellipsis-pre-str]
|
||||
[else
|
||||
(set! ellipsis-number (+ ellipsis-number 1))
|
||||
(format "..._r~a" ellipsis-number)]))
|
||||
(define ellipsis+name (datum->syntax
|
||||
(cadr terms)
|
||||
(string->symbol ellipsis-str)
|
||||
(cadr terms)))
|
||||
(record-binder ellipsis+name under)
|
||||
(define-values (fst-term fst-vars)
|
||||
(loop (car terms) (cons (syntax-e ellipsis+name) under)))
|
||||
(define-values (rst-terms rst-vars) (t-loop (cddr terms)))
|
||||
(values (cons `(repeat ,fst-term
|
||||
,ellipsis+name
|
||||
,(if mismatch? (cadr terms) #f))
|
||||
rst-terms)
|
||||
(append fst-vars rst-vars))]
|
||||
[else
|
||||
(define-values (fst-term fst-vars) (loop (car terms) under))
|
||||
(define-values (rst-terms rst-vars) (t-loop (cdr terms)))
|
||||
(values (cons fst-term rst-terms)
|
||||
(append fst-vars rst-vars))])))
|
||||
(values `(list ,@updated-terms) vars))]
|
||||
[else
|
||||
(when (pair? (syntax-e term))
|
||||
(let loop ([term term])
|
||||
(cond
|
||||
[(syntax? term) (loop (syntax-e term))]
|
||||
[(pair? term) (loop (cdr term))]
|
||||
[(null? term) (void)]
|
||||
[#t
|
||||
(raise-syntax-error what "dotted pairs not supported in patterns" orig-stx term)])))
|
||||
(values term '())])))
|
||||
|
||||
(define closed-table
|
||||
(make-immutable-hasheq (hash-map assignments (λ (cls _) (cons cls (find cls assignments))))))
|
||||
|
||||
(define repeat-id-counts (make-hash))
|
||||
|
||||
(define ellipsis-normalized
|
||||
(let loop ([pat term])
|
||||
(syntax-case pat (repeat)
|
||||
[(repeat sub-pat name mismatch-name)
|
||||
(let ()
|
||||
(define mapped-name (hash-ref closed-table (syntax-e #'name) #f))
|
||||
(define new-name (if mapped-name
|
||||
mapped-name
|
||||
(syntax-e #'name)))
|
||||
(hash-set! repeat-id-counts new-name (+ 1 (hash-ref repeat-id-counts new-name 0)))
|
||||
(let ([id (syntax-e #'mismatch-name)])
|
||||
(when id
|
||||
(hash-set! repeat-id-counts id (+ 1 (hash-ref repeat-id-counts id 0)))))
|
||||
#`(repeat #,(loop #'sub-pat) #,new-name mismatch-name))]
|
||||
[(a ...)
|
||||
(let ()
|
||||
(define new (map loop (syntax->list #'(a ...))))
|
||||
(if (syntax? pat)
|
||||
(datum->syntax pat new pat)
|
||||
new))]
|
||||
[_ pat])))
|
||||
|
||||
;(printf "term ~s\n" (syntax->datum (datum->syntax #'here term)))
|
||||
;(printf "norm ~s\n" (syntax->datum (datum->syntax #'here ellipsis-normalized)))
|
||||
;(printf "repeat-id-counts ~s\n" repeat-id-counts)
|
||||
|
||||
(define ellipsis-normalized/simplified
|
||||
(let loop ([pat ellipsis-normalized])
|
||||
(syntax-case pat (repeat)
|
||||
[(repeat sub-pat name mismatch-name)
|
||||
(let ()
|
||||
#`(repeat #,(loop #'sub-pat)
|
||||
#,(if (= 1 (hash-ref repeat-id-counts (syntax-e #'name)))
|
||||
#f
|
||||
#'name)
|
||||
#,(if (and (syntax-e #'mismatch-name)
|
||||
(= 1 (hash-ref repeat-id-counts (syntax-e #'mismatch-name))))
|
||||
#f
|
||||
#'mismatch-name)))]
|
||||
[(a ...)
|
||||
(let ()
|
||||
(define new (map loop (syntax->list #'(a ...))))
|
||||
(if (syntax? pat)
|
||||
(datum->syntax pat new pat)
|
||||
new))]
|
||||
[_ pat])))
|
||||
|
||||
(filter-duplicates what orig-stx names)
|
||||
(let ([without-mismatch-names (filter (λ (x) (not (id/depth-mismatch? x))) names)])
|
||||
(with-syntax ([(name/ellipses ...) (map build-dots without-mismatch-names)]
|
||||
[(name ...) (map id/depth-id without-mismatch-names)]
|
||||
[term ellipsis-normalized/simplified])
|
||||
#'(term (name ...) (name/ellipses ...)))))
|
||||
|
||||
(define-struct id/depth (id depth))
|
||||
(define-struct id/depth (id depth mismatch?))
|
||||
|
||||
;; extract-names : syntax syntax -> (values (listof syntax) (listof syntax[x | (x ...) | ((x ...) ...) | ...]))
|
||||
(define (extract-names all-nts what bind-names? orig-stx [mode 'rhs-only])
|
||||
|
@ -128,11 +349,11 @@
|
|||
(let loop ([stx orig-stx]
|
||||
[names null]
|
||||
[depth 0])
|
||||
(syntax-case stx (name in-hole side-condition cross)
|
||||
(syntax-case stx (name in-hole side-condition cross nt)
|
||||
[(name sym pat)
|
||||
(identifier? (syntax sym))
|
||||
(loop (syntax pat)
|
||||
(cons (make-id/depth (syntax sym) depth) names)
|
||||
(cons (make-id/depth (syntax sym) depth #f) names)
|
||||
depth)]
|
||||
[(in-hole pat1 pat2)
|
||||
(loop (syntax pat1)
|
||||
|
@ -163,7 +384,7 @@
|
|||
[(rhs-only) binds-in-right-hand-side?]
|
||||
[(binds-anywhere) binds?])
|
||||
all-nts bind-names? (syntax x)))
|
||||
(cons (make-id/depth (syntax x) depth) names)]
|
||||
(cons (make-id/depth (syntax x) depth #f) names)]
|
||||
[else names]))]
|
||||
[no-dups (filter-duplicates what orig-stx dups)])
|
||||
(values (map id/depth-id no-dups)
|
||||
|
@ -189,16 +410,16 @@
|
|||
(and (not (regexp-match #rx"^\\.\\.\\._" str))
|
||||
(not (regexp-match #rx"_!_" str))))))
|
||||
|
||||
(define (raise-ellipsis-depth-error what one-binder one-depth another-binder another-depth)
|
||||
(raise
|
||||
(make-exn:fail:syntax
|
||||
(format "~a: found the same binder, ~s, at different depths, ~a and ~a"
|
||||
what
|
||||
(syntax->datum one-binder)
|
||||
one-depth
|
||||
another-depth)
|
||||
(current-continuation-marks)
|
||||
(list one-binder another-binder))))
|
||||
(define (raise-ellipsis-depth-error what one-binder one-depth another-binder another-depth [orig-stx #f])
|
||||
(raise-syntax-error
|
||||
what
|
||||
(format "found the same binder, ~s, at different depths, ~a and ~a"
|
||||
(syntax->datum one-binder)
|
||||
one-depth
|
||||
another-depth)
|
||||
orig-stx
|
||||
another-binder
|
||||
(list one-binder)))
|
||||
|
||||
(define (filter-duplicates what orig-stx dups)
|
||||
(let loop ([dups dups])
|
||||
|
@ -216,6 +437,8 @@
|
|||
(raise-ellipsis-depth-error
|
||||
what
|
||||
(id/depth-id x) (id/depth-depth x)
|
||||
(id/depth-id (car dups)) (id/depth-depth (car dups)))))
|
||||
(id/depth-id (car dups)) (id/depth-depth (car dups))
|
||||
orig-stx)))
|
||||
(not same-id?)))
|
||||
(loop (cdr dups))))]))))
|
||||
(loop (cdr dups))))])))
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"term.rkt"
|
||||
"error.rkt"
|
||||
"struct.rkt"
|
||||
"match-a-pattern.rkt"
|
||||
(for-syntax racket/base
|
||||
"rewrite-side-conditions.rkt"
|
||||
"term-fn.rkt"
|
||||
|
@ -159,8 +160,9 @@
|
|||
(define-struct rg-lang (non-cross delayed-cross base-cases))
|
||||
(define (rg-lang-cross x) (force (rg-lang-delayed-cross x)))
|
||||
(define (prepare-lang lang)
|
||||
(let ([parsed (parse-language lang)])
|
||||
(values parsed (map symbol->string (compiled-lang-literals lang)) (find-base-cases parsed))))
|
||||
(values lang
|
||||
(map symbol->string (compiled-lang-literals lang))
|
||||
(find-base-cases lang)))
|
||||
|
||||
(define-struct (exn:fail:redex:generation-failure exn:fail:redex) ())
|
||||
(define (raise-gen-fail who what attempts)
|
||||
|
@ -198,7 +200,7 @@
|
|||
[size init-sz]
|
||||
[attempt init-att])
|
||||
(if (zero? remaining)
|
||||
(raise-gen-fail what (format "pattern ~a" name) retries)
|
||||
(raise-gen-fail what (format "pattern ~s" name) retries)
|
||||
(let-values ([(term env) (gen size attempt)])
|
||||
(if (pred term env)
|
||||
(values term env)
|
||||
|
@ -210,13 +212,16 @@
|
|||
pre-threshold-incr))))))))
|
||||
|
||||
(define (generate/prior name env gen)
|
||||
;(printf "generate/prior ~s ~s ~s\n" name env gen)
|
||||
(let* ([none (gensym)]
|
||||
[prior (hash-ref env name none)])
|
||||
(if (eq? prior none)
|
||||
(let-values ([(term env) (gen)])
|
||||
;(printf "generated ~s for ~s\n" term name)
|
||||
(values term (hash-set env name term)))
|
||||
(values prior env))))
|
||||
|
||||
|
||||
(define (generate-sequence gen env vars length)
|
||||
(define (split-environment env)
|
||||
(foldl (λ (var seq-envs)
|
||||
|
@ -252,7 +257,7 @@
|
|||
vals))))
|
||||
(for/and ([(name val) env])
|
||||
(or (not (mismatch? name))
|
||||
(let ([prior (get-group (mismatch-group name))])
|
||||
(let ([prior (get-group (mismatch-var name))])
|
||||
(and (not (hash-ref prior val #f))
|
||||
(hash-set! prior val #t))))))
|
||||
|
||||
|
@ -261,8 +266,8 @@
|
|||
(define (bindings env)
|
||||
(make-bindings
|
||||
(for/fold ([bindings null]) ([(key val) env])
|
||||
(if (binder? key)
|
||||
(cons (make-bind (binder-name key) val) bindings)
|
||||
(if (symbol? key)
|
||||
(cons (make-bind key val) bindings)
|
||||
bindings))))
|
||||
|
||||
(define-values (langp lits lang-bases) (prepare-lang lang))
|
||||
|
@ -270,6 +275,73 @@
|
|||
(define lit-syms (compiled-lang-literals lang))
|
||||
|
||||
(define (compile pat any?)
|
||||
|
||||
(define vars-table (make-hash))
|
||||
(define (find-vars pat) (hash-ref vars-table pat '()))
|
||||
(define mismatch-id 0)
|
||||
(define-values (rewritten-pat vars)
|
||||
(let loop ([pat pat])
|
||||
(define (add/ret pat vars)
|
||||
(hash-set! vars-table pat vars)
|
||||
(values pat vars))
|
||||
(define (build-mismatch var)
|
||||
(set! mismatch-id (+ mismatch-id 1))
|
||||
(make-mismatch mismatch-id var))
|
||||
(match-a-pattern pat
|
||||
[`any (values pat '())]
|
||||
[`number (values pat '())]
|
||||
[`string (values pat '())]
|
||||
[`natural (values pat '())]
|
||||
[`integer (values pat '())]
|
||||
[`real (values pat '())]
|
||||
[`variable (values pat '())]
|
||||
[`(variable-except ,vars ...) (values pat '())]
|
||||
[`(variable-prefix ,var) (values pat '())]
|
||||
[`variable-not-otherwise-mentioned (values pat '())]
|
||||
[`hole (values pat '())]
|
||||
[`(nt ,x) (values pat '())]
|
||||
[`(name ,name ,p)
|
||||
(define-values (p-rewritten p-names) (loop p))
|
||||
(add/ret `(name ,name ,p-rewritten) (cons name p-names))]
|
||||
[`(mismatch-name ,name ,p)
|
||||
(define mm (build-mismatch name))
|
||||
(define-values (p-rewritten p-names) (loop p))
|
||||
(add/ret `(mismatch-name ,mm ,p-rewritten)
|
||||
(cons mm p-names))]
|
||||
[`(in-hole ,p1 ,p2)
|
||||
(define-values (p1-rewritten p1-names) (loop p1))
|
||||
(define-values (p2-rewritten p2-names) (loop p2))
|
||||
(add/ret `(in-hole ,p1-rewritten ,p2-rewritten)
|
||||
(append p1-names p2-names))]
|
||||
[`(hide-hole ,p)
|
||||
(define-values (p-rewritten p-names) (loop p))
|
||||
(add/ret `(hide-hole ,p-rewritten) p-names)]
|
||||
[`(side-condition ,p ,e ,e2)
|
||||
(define-values (p-rewritten p-names) (loop p))
|
||||
(add/ret `(side-condition ,p-rewritten ,e ,e2) p-names)]
|
||||
[`(cross ,var) (values pat '())]
|
||||
[`(list ,lpats ...)
|
||||
(define-values (lpats-rewritten vars)
|
||||
(for/fold ([ps-rewritten '()]
|
||||
[vars '()])
|
||||
([lpat (in-list lpats)])
|
||||
(match lpat
|
||||
[`(repeat ,p ,name ,mismatch-name)
|
||||
(define l1 (if name (list name) '()))
|
||||
(define mm (and mismatch-name
|
||||
(build-mismatch mismatch-name)))
|
||||
(define l2 (if mm (cons mm l1) l1))
|
||||
(define-values (p-rewritten p-vars) (loop p))
|
||||
(values (cons `(repeat ,p-rewritten ,name ,mm) ps-rewritten)
|
||||
(append l2 p-vars vars))]
|
||||
[_
|
||||
(define-values (p-rewritten p-vars) (loop lpat))
|
||||
(values (cons p-rewritten ps-rewritten)
|
||||
(append p-vars vars))])))
|
||||
(add/ret `(list ,@(reverse lpats-rewritten))
|
||||
vars)]
|
||||
[(? (compose not pair?)) (values pat '())])))
|
||||
|
||||
(let* ([nt? (is-nt? (if any? sexpp langp))]
|
||||
[mismatches? #f]
|
||||
[generator
|
||||
|
@ -291,12 +363,19 @@
|
|||
; (W hole
|
||||
; ; extra parens to avoid matcher loop
|
||||
; (in-hole (W_1) (+ natural hole))))
|
||||
(let recur ([pat pat])
|
||||
(match pat
|
||||
(let recur ([pat rewritten-pat])
|
||||
(match-a-pattern pat
|
||||
[`any
|
||||
(λ (r s a e f)
|
||||
(let*-values ([(lang nt) ((next-any-decision) langc sexpc)]
|
||||
[(term) (gen-nt lang nt #f r s a the-not-hole)])
|
||||
(values term e)))]
|
||||
[`number (generator/attempts (λ (a) ((next-number-decision) a)))]
|
||||
[`string (generator/attempts (λ (a) ((next-string-decision) lits a)))]
|
||||
[`natural (generator/attempts (λ (a) ((next-natural-decision) a)))]
|
||||
[`integer (generator/attempts (λ (a) ((next-integer-decision) a)))]
|
||||
[`real (generator/attempts (λ (a) ((next-real-decision) a)))]
|
||||
[`variable (generator/attempts (λ (a) ((next-variable-decision) lits a)))]
|
||||
[`(variable-except ,vars ...)
|
||||
(let ([g (recur 'variable)])
|
||||
(λ (r s a e f)
|
||||
|
@ -304,14 +383,6 @@
|
|||
(λ (s a) (g r s a e f))
|
||||
(λ (var _) (not (memq var vars)))
|
||||
s a r)))]
|
||||
[`variable (generator/attempts (λ (a) ((next-variable-decision) lits a)))]
|
||||
[`variable-not-otherwise-mentioned
|
||||
(let ([g (recur 'variable)])
|
||||
(λ (r s a e f)
|
||||
(generate/pred pat
|
||||
(λ (s a) (g r s a e f))
|
||||
(λ (var _) (not (memq var lit-syms)))
|
||||
s a r)))]
|
||||
[`(variable-prefix ,prefix)
|
||||
(define (symbol-append prefix suffix)
|
||||
(string->symbol (string-append (symbol->string prefix) (symbol->string suffix))))
|
||||
|
@ -319,20 +390,27 @@
|
|||
(λ (r s a e f)
|
||||
(let-values ([(t e) (g r s a e f)])
|
||||
(values (symbol-append prefix t) e))))]
|
||||
[`string (generator/attempts (λ (a) ((next-string-decision) lits a)))]
|
||||
[`(side-condition ,pat ,(? procedure? condition) ,guard-src-loc)
|
||||
(let ([g (recur pat)])
|
||||
[`variable-not-otherwise-mentioned
|
||||
(let ([g (recur 'variable)])
|
||||
(λ (r s a e f)
|
||||
(generate/pred `(side-condition ,(unparse-pattern pat) ,guard-src-loc)
|
||||
(generate/pred pat
|
||||
(λ (s a) (g r s a e f))
|
||||
(λ (_ env) (condition (bindings env)))
|
||||
(λ (var _) (not (memq var lit-syms)))
|
||||
s a r)))]
|
||||
[`(name ,(? symbol? id) ,p)
|
||||
[`hole (λ (r s a e f) (values f e))]
|
||||
[`(nt ,nt-id)
|
||||
(λ (r s a e f)
|
||||
(values (gen-nt (if any? sexpc langc) nt-id #f r s a f) e))]
|
||||
[`(name ,id ,p)
|
||||
(let ([g (recur p)])
|
||||
(λ (r s a e f)
|
||||
(let-values ([(t env) (g r s a e f)])
|
||||
(values t (hash-set env (make-binder id) t)))))]
|
||||
[`hole (λ (r s a e f) (values f e))]
|
||||
(generate/prior id e (λ () (g r s a e f)))))]
|
||||
[`(mismatch-name ,id ,pat)
|
||||
(let ([g (recur pat)])
|
||||
(set! mismatches? #t)
|
||||
(λ (r s a e f)
|
||||
(let-values ([(t e) (g r s a e f)])
|
||||
(values t (hash-set e id t)))))]
|
||||
[`(in-hole ,context ,filler)
|
||||
(let ([c-context (recur context)]
|
||||
[c-filler (recur filler)])
|
||||
|
@ -344,54 +422,50 @@
|
|||
(let ([g (recur pattern)])
|
||||
(λ (r s a e f)
|
||||
(g r s a e the-not-hole)))]
|
||||
[`any
|
||||
[`(side-condition ,pat ,(? procedure? condition) ,guard-src-loc)
|
||||
(let ([g (recur pat)])
|
||||
(λ (r s a e f)
|
||||
(generate/pred `(side-condition ,(unparse-pattern pat) ,guard-src-loc)
|
||||
(λ (s a) (g r s a e f))
|
||||
(λ (_ env) (condition (bindings env)))
|
||||
s a r)))]
|
||||
[`(cross ,(? symbol? p))
|
||||
(λ (r s a e f)
|
||||
(let*-values ([(lang nt) ((next-any-decision) langc sexpc)]
|
||||
[(term) (gen-nt lang nt #f r s a the-not-hole)])
|
||||
(values term e)))]
|
||||
[(or (? symbol? (? nt? p)) `(cross ,(? symbol? p)))
|
||||
(let ([cross? (not (symbol? pat))])
|
||||
(λ (r s a e f)
|
||||
(values (gen-nt (if any? sexpc langc) p cross? r s a f) e)))]
|
||||
[(? binder?)
|
||||
(let ([g (recur (binder-pattern pat))])
|
||||
(λ (r s a e f)
|
||||
(generate/prior pat e (λ () (g r s a e f)))))]
|
||||
[(? mismatch?)
|
||||
(let ([g (recur (mismatch-pattern pat))])
|
||||
(set! mismatches? #t)
|
||||
(λ (r s a e f)
|
||||
(let-values ([(t e) (g r s a e f)])
|
||||
(values t (hash-set e pat t)))))]
|
||||
[(or (? symbol?) (? number?) (? string?) (? boolean?) (? null?))
|
||||
(λ (r s a e f) (values pat e))]
|
||||
[(list-rest (struct ellipsis (name sub-pat class vars)) rest)
|
||||
(let ([elemg (recur sub-pat)]
|
||||
[tailg (recur rest)])
|
||||
(when (mismatch? name)
|
||||
(set! mismatches? #t))
|
||||
(λ (r s a e f)
|
||||
(let*-values ([(len)
|
||||
(let ([prior (hash-ref e class #f)])
|
||||
(if prior
|
||||
prior
|
||||
(if (zero? s) 0 ((next-sequence-decision) s))))]
|
||||
[(seq env)
|
||||
(generate-sequence (λ (e) (elemg r s a e f)) e vars len)]
|
||||
[(tail env)
|
||||
(let ([e (hash-set (hash-set env class len) name len)])
|
||||
(tailg r s a e f))])
|
||||
(values (append seq tail) env))))]
|
||||
[(list-rest hdp tlp)
|
||||
(let ([hdg (recur hdp)]
|
||||
[tlg (recur tlp)])
|
||||
(λ (r s a e f)
|
||||
(let*-values
|
||||
([(hd env) (hdg r s a e f)]
|
||||
[(tl env) (tlg r s a env f)])
|
||||
(values (cons hd tl) env))))]
|
||||
[else
|
||||
(error what "unknown pattern ~s\n" pat)]))])
|
||||
(values (gen-nt (if any? sexpc langc) p #t r s a f) e))]
|
||||
|
||||
[`(list ,in-lpats ...)
|
||||
(let loop ([lpats in-lpats])
|
||||
(match lpats
|
||||
[`() (λ (r s a e f) (values '() e))]
|
||||
[(cons `(repeat ,sub-pat ,name ,mismatch-name) rst)
|
||||
(let ([elemg (recur sub-pat)]
|
||||
[tailg (loop rst)]
|
||||
[vars (find-vars sub-pat)])
|
||||
(when mismatch-name
|
||||
(set! mismatches? #t))
|
||||
(λ (r s a env0 f)
|
||||
(define len
|
||||
(let ([prior (and name (hash-ref env0 name #f))])
|
||||
(if prior
|
||||
prior
|
||||
(if (zero? s) 0 ((next-sequence-decision) s)))))
|
||||
(let*-values ([(seq env) (generate-sequence (λ (e) (elemg r s a e f)) env0 vars len)]
|
||||
[(env) (if name (hash-set env name len) env)]
|
||||
[(env) (if mismatch-name
|
||||
(hash-set env mismatch-name len)
|
||||
env)]
|
||||
[(tail env) (tailg r s a env f)])
|
||||
(values (append seq tail) env))))]
|
||||
[(cons hdp tlp)
|
||||
(let ([hdg (recur hdp)]
|
||||
[tlg (loop tlp)])
|
||||
(λ (r s a env f)
|
||||
(let*-values
|
||||
([(hd env) (hdg r s a env f)]
|
||||
[(tl env) (tlg r s a env f)])
|
||||
(values (cons hd tl) env))))]))]
|
||||
[(? (compose not pair?))
|
||||
(λ (r s a e f) (values pat e))]))])
|
||||
(if mismatches?
|
||||
(λ (r s a e f)
|
||||
(let ([g (λ (s a) (generator r s a e f))]
|
||||
|
@ -413,7 +487,7 @@
|
|||
(define sexpc (compile-language sexpp sexp-bases #t))
|
||||
(define (compile-pattern pat) (compile pat #f))
|
||||
(λ (pat)
|
||||
(define g (compile-pattern (reassign-classes (parse-pattern pat lang 'top-level))))
|
||||
(define g (compile-pattern pat))
|
||||
(λ (size attempt retries)
|
||||
(define-values (t e) (g retries size attempt empty-env the-hole))
|
||||
(values (let replace-the-not-hole ([t t])
|
||||
|
@ -450,27 +524,34 @@
|
|||
(define (rhs->nts pat)
|
||||
(let ([nts '()])
|
||||
(let loop ([pat pat])
|
||||
(match pat
|
||||
[(? binder?)
|
||||
(set! nts (cons (cons #f (binder-pattern pat)) nts))]
|
||||
[(? mismatch?)
|
||||
(set! nts (cons (cons #f (mismatch-pattern pat)) nts))]
|
||||
[(? symbol?)
|
||||
(when ((is-nt? lang) pat)
|
||||
(set! nts (cons (cons #f pat) nts)))]
|
||||
[`(cross ,(? symbol? x-nt))
|
||||
(match-a-pattern pat
|
||||
[`any (void)]
|
||||
[`number (void)]
|
||||
[`string (void)]
|
||||
[`natural (void)]
|
||||
[`integer (void)]
|
||||
[`real (void)]
|
||||
[`variable (void)]
|
||||
[`(variable-except ,vars ...) (void)]
|
||||
[`(variable-prefix ,var) (void)]
|
||||
[`variable-not-otherwise-mentioned (void)]
|
||||
[`hole (void)]
|
||||
[`(nt ,var) (set! nts (cons (cons #f var) nts))]
|
||||
[`(name ,n ,p) (loop p)]
|
||||
[`(mismatch-name ,n ,p) (loop p)]
|
||||
[`(in-hole ,p1 ,p2) (loop p1) (loop p2)]
|
||||
[`(hide-hole ,p) (loop p)]
|
||||
[`(side-condition ,p ,exp ,info) (loop p)]
|
||||
[`(cross ,x-nt)
|
||||
(set! nts (cons (cons #t x-nt) nts))]
|
||||
[`(variable-except ,s ...) (void)]
|
||||
[`(variable-prefix ,p) (void)]
|
||||
[`(name ,_ ,p) (loop p)]
|
||||
[`() (void)]
|
||||
[(struct ellipsis (_ p _ _))
|
||||
(loop p)]
|
||||
[`(,a . ,b)
|
||||
(loop a)
|
||||
(loop b)]
|
||||
[_ (void)]))
|
||||
nts))
|
||||
[`(list ,lpats ...)
|
||||
(for ([lpat (in-list lpats)])
|
||||
(match lpat
|
||||
[`(repeat ,p ,name ,mismatch?)
|
||||
(loop p)]
|
||||
[_ (loop lpat)]))]
|
||||
[(? (compose not pair?)) (void)]))
|
||||
nts))
|
||||
|
||||
;; build-table : (listof nt) -> hash
|
||||
(define (build-table nts)
|
||||
|
@ -547,15 +628,11 @@
|
|||
(let ([match (regexp-match rx (symbol->string x))])
|
||||
(and match (cadr match) (string->symbol (cadr match))))))
|
||||
|
||||
(define-struct class (id) #:inspector (make-inspector))
|
||||
(define-struct class (id) #:transparent)
|
||||
|
||||
(define-struct mismatch (id group) #:inspector (make-inspector))
|
||||
(define mismatch-pattern
|
||||
(match-lambda
|
||||
[(struct mismatch (_ name))
|
||||
((symbol-match mismatch-nt-rx) name)]))
|
||||
(define-struct mismatch (id var) #:transparent)
|
||||
|
||||
(define-struct binder (name) #:inspector (make-inspector))
|
||||
(define-struct binder (name) #:transparent)
|
||||
(define binder-pattern
|
||||
(match-lambda
|
||||
[(struct binder (name))
|
||||
|
@ -574,76 +651,13 @@
|
|||
;; and after generating an ellipsis
|
||||
(define-struct ellipsis (name pattern class vars) #:inspector (make-inspector))
|
||||
|
||||
;; parse-pattern : pattern compiled-lang (or/c 'cross 'top-level 'grammar) -> parsed-pattern
|
||||
;; Turns "pat ...", "pat ..._id", and "pat ..._!_id" into ellipsis structs,
|
||||
;; "nt_!_id" into mismatch structs, "nt_id" into binder structs, and
|
||||
;; "nt/underscore-allowed" in top-level patterns into binder structs.
|
||||
(define (parse-pattern pattern lang mode)
|
||||
(define (recur pat vars)
|
||||
(match pat
|
||||
[(or (app (symbol-match named-nt-rx) (or (? (is-nt? lang)) (? built-in?)))
|
||||
(and (? (λ (_) (eq? mode 'top-level))) (or (? (is-nt? lang)) (? built-in?))))
|
||||
(let ([b (make-binder pat)])
|
||||
(values b (cons b vars)))]
|
||||
[(app (symbol-match mismatch-nt-rx) (or (? (is-nt? lang)) (? built-in?)))
|
||||
(let ([mismatch (make-mismatch (gensym) pat)])
|
||||
(values mismatch (cons mismatch vars)))]
|
||||
[`(name ,name ,sub-pat)
|
||||
(let-values ([(parsed vars) (recur sub-pat vars)])
|
||||
(values `(name ,name ,parsed) (cons (make-binder name) vars)))]
|
||||
[(list-rest sub-pat (and (? symbol?) (app symbol->string (regexp named-ellipsis-rx)) name) rest)
|
||||
(let*-values ([(sub-pat-parsed sub-pat-vars) (recur sub-pat null)]
|
||||
[(seq) (make-ellipsis name sub-pat-parsed (make-class name) sub-pat-vars)]
|
||||
[(vars) (append (list* name (make-class name) sub-pat-vars) vars)]
|
||||
[(rest-parsed vars) (recur rest vars)])
|
||||
(values (cons seq rest-parsed) vars))]
|
||||
[(list-rest sub-pat '... rest)
|
||||
(let*-values ([(sub-pat-parsed sub-pat-vars) (recur sub-pat null)]
|
||||
[(class) (make-class (gensym))]
|
||||
[(seq) (make-ellipsis '... sub-pat-parsed class sub-pat-vars)]
|
||||
[(rest-parsed vars) (recur rest (cons class (append sub-pat-vars vars)))])
|
||||
(values (cons seq rest-parsed) vars))]
|
||||
[(list-rest sub-pat (and (? symbol?) (app symbol->string (regexp mismatch-ellipsis-rx)) name) rest)
|
||||
(let*-values ([(sub-pat-parsed sub-pat-vars) (recur sub-pat null)]
|
||||
[(mismatch) (make-mismatch (gensym) name)]
|
||||
[(class) (make-class (gensym))]
|
||||
[(seq) (make-ellipsis mismatch sub-pat-parsed class sub-pat-vars)]
|
||||
[(vars) (append (list* class mismatch sub-pat-vars) vars)]
|
||||
[(rest-parsed vars) (recur rest vars)])
|
||||
(values (cons seq rest-parsed) vars))]
|
||||
[(and (? (λ (_) (not (eq? mode 'cross)))) `(cross ,(and (? (is-nt? lang)) nt)))
|
||||
(let ([nt-str (symbol->string nt)])
|
||||
(values `(cross ,(string->symbol (string-append nt-str "-" nt-str))) vars))]
|
||||
[`(side-condition ,pat ,guard ,guard-src-loc)
|
||||
(let-values ([(parsed vars) (recur pat vars)])
|
||||
(values `(side-condition ,parsed ,guard ,guard-src-loc) vars))]
|
||||
[(cons first rest)
|
||||
(let-values ([(first-parsed vars) (recur first vars)])
|
||||
(let-values ([(rest-parsed vars) (recur rest vars)])
|
||||
(values (cons first-parsed rest-parsed) vars)))]
|
||||
[_ (values pat vars)]))
|
||||
(let-values ([(parsed _) (recur pattern null)])
|
||||
parsed))
|
||||
|
||||
;; parse-language: compiled-lang -> compiled-lang
|
||||
(define (parse-language lang)
|
||||
(define ((parse-nt mode) nt)
|
||||
(make-nt (nt-name nt) (map (parse-rhs mode) (nt-rhs nt))))
|
||||
(define ((parse-rhs mode) rhs)
|
||||
(make-rhs (reassign-classes (parse-pattern (rhs-pattern rhs) lang mode))))
|
||||
|
||||
(struct-copy
|
||||
compiled-lang lang
|
||||
[lang (map (parse-nt 'grammar) (compiled-lang-lang lang))]
|
||||
[delayed-cclang (delay (map (parse-nt 'cross) (compiled-lang-cclang lang)))]))
|
||||
|
||||
;; unparse-pattern: parsed-pattern -> pattern
|
||||
(define unparse-pattern
|
||||
(match-lambda
|
||||
[(struct binder (name)) name]
|
||||
[(struct mismatch (_ group)) group]
|
||||
[(struct mismatch (id var)) var]
|
||||
[(list-rest (struct ellipsis (name sub-pat _ _)) rest)
|
||||
(let ([ellipsis (if (mismatch? name) (mismatch-group name) name)])
|
||||
(let ([ellipsis (if (mismatch? name) (mismatch-var name) name)])
|
||||
(list* (unparse-pattern sub-pat) ellipsis (unparse-pattern rest)))]
|
||||
[(cons first rest)
|
||||
(cons (unparse-pattern first) (unparse-pattern rest))]
|
||||
|
@ -659,31 +673,54 @@
|
|||
(if (and par (not (eq? chd par))) (recur par (hash-ref sets par #f)) chd)))
|
||||
|
||||
(let* ([last-contexts (make-hasheq)]
|
||||
[assignments #hasheq()]
|
||||
[record-binder
|
||||
(λ (pat under assignments)
|
||||
(if (null? under)
|
||||
assignments
|
||||
(let ([last (hash-ref last-contexts pat #f)])
|
||||
(if last
|
||||
(foldl (λ (cur last asgns) (union cur last asgns)) assignments under last)
|
||||
(begin
|
||||
(hash-set! last-contexts pat under)
|
||||
assignments)))))]
|
||||
[assignments
|
||||
(let recur ([pat pattern] [under null] [assignments #hasheq()])
|
||||
(match pat
|
||||
;; `(name ,id ,sub-pat) not considered, since bindings introduced
|
||||
;; by name must be unique.
|
||||
[(struct binder (name))
|
||||
(record-binder name under assignments)]
|
||||
[(struct ellipsis (name sub-pat (struct class (cls)) _))
|
||||
(recur sub-pat (cons cls under)
|
||||
(if (and (symbol? name) (regexp-match named-ellipsis-rx (symbol->string name)))
|
||||
(record-binder name under assignments)
|
||||
assignments))]
|
||||
[(? list?)
|
||||
(foldl (λ (pat asgns) (recur pat under asgns)) assignments pat)]
|
||||
[_ assignments]))])
|
||||
(λ (pat under)
|
||||
(set! assignments
|
||||
(if (null? under)
|
||||
assignments
|
||||
(let ([last (hash-ref last-contexts pat #f)])
|
||||
(if last
|
||||
(foldl (λ (cur last asgns) (union cur last asgns)) assignments under last)
|
||||
(begin
|
||||
(hash-set! last-contexts pat under)
|
||||
assignments))))))])
|
||||
(let recur ([pat pattern] [under null])
|
||||
(match-a-pattern pat
|
||||
[`any assignments]
|
||||
[`number assignments]
|
||||
[`string assignments]
|
||||
[`natural assignments]
|
||||
[`integer assignments]
|
||||
[`real assignments]
|
||||
[`variable assignments]
|
||||
[`(variable-except ,vars ...) assignments]
|
||||
[`(variable-prefix ,var) assignments]
|
||||
[`variable-not-otherwise-mentioned assignments]
|
||||
[`hole assignments]
|
||||
[`(nt ,var) assignments]
|
||||
[`(name ,var ,pat)
|
||||
(record-binder var under)
|
||||
(recur pat under)]
|
||||
[`(mismatch-name ,var ,pat)
|
||||
(recur pat under)]
|
||||
[`(in-hole ,p1 ,p2)
|
||||
(recur p2 under)
|
||||
(recur p1 under)]
|
||||
[`(hide-hole ,p)
|
||||
(recur p under)]
|
||||
[`(side-condition ,p ,exp ,srcloc)
|
||||
(recur p under)]
|
||||
[`(cross ,nt) assignments]
|
||||
[`(list ,lpats ...)
|
||||
(for ([lpat (in-list lpats)])
|
||||
(match lpat
|
||||
[`(repeat ,p ,name ,mismatch?)
|
||||
(record-binder name under)
|
||||
(recur p (cons (or name (gensym)) under))]
|
||||
[else (recur lpat under)]))
|
||||
assignments]
|
||||
[(? (compose not pair?)) assignments]))
|
||||
(make-immutable-hasheq (hash-map assignments (λ (cls _) (cons cls (find cls assignments)))))))
|
||||
|
||||
(define (reassign-classes pattern)
|
||||
|
@ -691,6 +728,11 @@
|
|||
[rewrite (λ (c) (make-class (hash-ref reassignments (class-id c) (class-id c))))])
|
||||
(let recur ([pat pattern])
|
||||
(match pat
|
||||
#;
|
||||
[`(repeat ,sub-pat ,name ,mismatch?)
|
||||
`(repeat ,(recur sub-pat)
|
||||
,(rewrite name)
|
||||
,mismatch?)]
|
||||
[(struct ellipsis (name sub-pat class vars))
|
||||
(make-ellipsis name (recur sub-pat) (rewrite class)
|
||||
(map (λ (v) (if (class? v) (rewrite v) v)) vars))]
|
||||
|
@ -710,7 +752,7 @@
|
|||
(if m m (raise-syntax-error #f "not a metafunction" stx name))))
|
||||
|
||||
(define-for-syntax (term-generator lang pat what)
|
||||
(with-syntax ([pattern
|
||||
(with-syntax ([(pattern (vars ...) (vars/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs
|
||||
(language-id-nts lang what)
|
||||
what #t pat)])
|
||||
|
@ -1067,8 +1109,8 @@
|
|||
(provide pick-from-list pick-sequence-length pick-nts
|
||||
pick-char pick-var pick-string pick-any
|
||||
pick-number pick-natural pick-integer pick-real
|
||||
parse-pattern unparse-pattern
|
||||
parse-language prepare-lang
|
||||
unparse-pattern
|
||||
prepare-lang
|
||||
class-reassignments reassign-classes
|
||||
default-retries proportion-at-size
|
||||
retry-threshold proportion-before-threshold post-threshold-incr
|
||||
|
|
|
@ -171,7 +171,7 @@
|
|||
|
||||
(test (send annotations collected-rename-class def-name)
|
||||
(expected-rename-class (list def-name use-name)))
|
||||
(test (send annotations collected-rename-class def-name)
|
||||
(test (send annotations collected-rename-class use-name)
|
||||
(expected-rename-class (list def-name use-name))))
|
||||
|
||||
(print-tests-passed 'check-syntax-test.rkt)
|
File diff suppressed because it is too large
Load Diff
134
collects/redex/tests/rewrite-side-condition-test.rkt
Normal file
134
collects/redex/tests/rewrite-side-condition-test.rkt
Normal file
|
@ -0,0 +1,134 @@
|
|||
#lang racket/base
|
||||
(require (for-syntax "../private/rewrite-side-conditions.rkt"
|
||||
racket/base)
|
||||
"../private/term.rkt" ;; to get bindings for 'in-hole' etc
|
||||
rackunit)
|
||||
|
||||
(define-syntax (rsc stx)
|
||||
(syntax-case stx ()
|
||||
[(_ pat (nts ...) bind-names?)
|
||||
(with-syntax ([(pat (vars ...) (vars/ellipses ...))
|
||||
(rewrite-side-conditions/check-errs
|
||||
(syntax->datum #'(nts ...))
|
||||
'rsc
|
||||
(syntax-e #'bind-names?)
|
||||
#'pat)])
|
||||
#'(list `pat
|
||||
`(vars ...)
|
||||
`(vars/ellipses ...)))]))
|
||||
|
||||
(check-equal? (rsc 1 () #t) `(1 () ()))
|
||||
(check-equal? (rsc (1) () #t) `((list 1) () ()))
|
||||
(check-equal? (rsc (1 ...) () #t) `((list (repeat 1 #f #f)) () ()))
|
||||
(check-equal? (rsc (1 ..._2) () #t) `((list (repeat 1 #f #f)) () ()))
|
||||
(check-equal? (rsc (1 ..._2 1 ..._2) () #t) `((list (repeat 1 ..._2 #f) (repeat 1 ..._2 #f)) () ()))
|
||||
(check-equal? (rsc (1 ..._!_3) () #t) `((list (repeat 1 #f #f)) () ()))
|
||||
(check-equal? (rsc (1 ..._!_3 1 ..._!_3) () #t) `((list (repeat 1 #f ..._!_3) (repeat 1 #f ..._!_3)) () ()))
|
||||
|
||||
(check-equal? (rsc x (x) #t) `((name x (nt x)) (x) (x)))
|
||||
(check-equal? (rsc x (x) #f) `((nt x) () ()))
|
||||
(check-equal? (rsc x_1 (x) #t) `((name x_1 (nt x)) (x_1) (x_1)))
|
||||
(check-equal? (rsc x_1 (x) #f) `((name x_1 (nt x)) (x_1) (x_1)))
|
||||
(check-equal? (rsc any (x) #t) `((name any any) (any) (any)))
|
||||
(check-equal? (rsc any (x) #f) `(any () ()))
|
||||
(check-equal? (rsc any_1 (x) #t) `((name any_1 any) (any_1) (any_1)))
|
||||
(check-equal? (rsc any_1 (x) #f) `((name any_1 any) (any_1) (any_1)))
|
||||
(check-equal? (rsc ((x ...) ...) (x) #t)
|
||||
`((list (repeat (list (repeat (name x (nt x)) #f #f)) #f #f))
|
||||
(x)
|
||||
(((x ...) ...))))
|
||||
|
||||
(check-equal? (rsc (in-hole (hole a #f (hide-hole hole)) (cross x)) '(x) #f)
|
||||
`((in-hole (list hole a #f (hide-hole hole)) (cross x-x))
|
||||
()
|
||||
()))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; test the normalization of the ellipses underscores
|
||||
;;
|
||||
(check-equal? (car (rsc (x_1 ..._1 x_2 ..._2 x_2 ..._1) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_2 (nt x)) ..._1 #f)
|
||||
(repeat (name x_2 (nt x)) ..._1 #f)))
|
||||
(check-equal? (car (rsc ((x_1 ..._1 x_1 ..._2) (x_2 ..._1 x_2 ..._2) x_3 ..._2) (x) #t))
|
||||
'(list (list (repeat (name x_1 (nt x)) ..._2 #f)
|
||||
(repeat (name x_1 (nt x)) ..._2 #f))
|
||||
(list (repeat (name x_2 (nt x)) ..._2 #f)
|
||||
(repeat (name x_2 (nt x)) ..._2 #f))
|
||||
(repeat (name x_3 (nt x)) ..._2 #f)))
|
||||
(check-equal? (car (rsc (x_1 ..._1 x ..._2 x_1 ..._2) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._2 #f)
|
||||
(repeat (name x (nt x)) ..._2 #f)
|
||||
(repeat (name x_1 (nt x)) ..._2 #f)))
|
||||
|
||||
|
||||
(check-equal? (car (rsc (x_1 ..._1 x_2 ..._2 (x_1 x_2) ..._3) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._3 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f)
|
||||
(repeat (list (name x_1 (nt x)) (name x_2 (nt x))) ..._3 #f)))
|
||||
(check-equal? (car (rsc ((x_1 ..._1) ..._2 x_2 ..._3 (x_1 ..._4 x_2) ..._5) (x) #t))
|
||||
'(list (repeat (list (repeat (name x_1 (nt x)) ..._4 #f)) ..._5 #f)
|
||||
(repeat (name x_2 (nt x)) ..._5 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._4 #f)
|
||||
(name x_2 (nt x)))
|
||||
..._5
|
||||
#f)))
|
||||
(check-equal? (car (rsc ((x_1 ..._1) ..._2 (x_1 ..._3) ..._4 (x_1 ..._5) ..._6) (x) #t))
|
||||
'(list (repeat (list (repeat (name x_1 (nt x)) ..._5 #f)) ..._6 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._5 #f)) ..._6 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._5 #f)) ..._6 #f)))
|
||||
|
||||
(check-equal? (car (rsc (x_1 ..._1 x_1 ..._2 x_2 ..._1 x_2 ..._4 x_2 ..._3) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._3 #f)
|
||||
(repeat (name x_1 (nt x)) ..._3 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f)))
|
||||
|
||||
(check-equal? (car (rsc (x_1 ... x_1 ..._!_1 x_1 ..._1) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_1 (nt x)) ..._1 #f)))
|
||||
|
||||
(check-equal? (car (rsc (x_1 ... x_1 ..._!_1 x_1 ..._1 x_2 ..._!_1) (x) #t))
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_1 (nt x)) ..._1 ..._!_1)
|
||||
(repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_2 (nt x)) #f ..._!_1)))
|
||||
|
||||
(check-equal? (car (rsc ((3 ..._1) ..._2 (4 ..._1) ..._3) (x) #t))
|
||||
'(list (repeat (list (repeat 3 ..._1 #f)) ..._3 #f)
|
||||
(repeat (list (repeat 4 ..._1 #f)) ..._3 #f)))
|
||||
|
||||
(check-equal? (car (rsc (x ..._1 x ..._2
|
||||
variable ..._2 variable ..._3 variable_1 ..._3 variable_1 ..._4)
|
||||
(x) #t))
|
||||
'(list (repeat (name x (nt x)) ..._4 #f)
|
||||
(repeat (name x (nt x)) ..._4 #f)
|
||||
(repeat (name variable variable) ..._4 #f)
|
||||
(repeat (name variable variable) ..._4 #f)
|
||||
(repeat (name variable_1 variable) ..._4 #f)
|
||||
(repeat (name variable_1 variable) ..._4 #f)))
|
||||
|
||||
(check-equal? (car (rsc (z_1 ... z_2 ..._!_1 (z_1 z_2) ...) (z) #t))
|
||||
'(list (repeat (name z_1 (nt z)) ..._r3 #f)
|
||||
(repeat (name z_2 (nt z)) ..._r3 #f)
|
||||
(repeat (list (name z_1 (nt z))
|
||||
(name z_2 (nt z)))
|
||||
..._r3
|
||||
#f)))
|
||||
|
||||
(check-equal? (car (rsc (z_1 ... z_2 ..._!_1 z_3 ..._!_1 (z_1 z_2) ...) (z) #t))
|
||||
'(list (repeat (name z_1 (nt z)) ..._r4 #f)
|
||||
(repeat (name z_2 (nt z)) ..._r4 ..._!_1)
|
||||
(repeat (name z_3 (nt z)) #f ..._!_1)
|
||||
(repeat (list (name z_1 (nt z))
|
||||
(name z_2 (nt z)))
|
||||
..._r4
|
||||
#f)))
|
||||
|
||||
;;
|
||||
;; test the normalization of the ellipses underscores
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
@ -43,14 +43,11 @@
|
|||
[(exn:fail:redex:test _ _ (? exn:fail:contract:blame? e) _) e]
|
||||
[x x])))]))
|
||||
|
||||
(define find-base-cases/unparsed
|
||||
(compose find-base-cases parse-language))
|
||||
|
||||
(let ()
|
||||
(define-language lc
|
||||
(e x (e e) (λ (x) e))
|
||||
(x variable))
|
||||
(let ([bc (find-base-cases/unparsed lc)])
|
||||
(let ([bc (find-base-cases lc)])
|
||||
(test (to-table (base-cases-non-cross bc))
|
||||
'((e . (1 2 2)) (x . (0))))
|
||||
(test (to-table (base-cases-cross bc))
|
||||
|
@ -59,7 +56,7 @@
|
|||
(let ()
|
||||
(define-language lang
|
||||
(e (e e)))
|
||||
(let ([bc (find-base-cases/unparsed lang)])
|
||||
(let ([bc (find-base-cases lang)])
|
||||
(test (to-table (base-cases-non-cross bc)) '((e . (inf))))
|
||||
(test (to-table (base-cases-cross bc)) '((e-e . (0 inf inf))))))
|
||||
|
||||
|
@ -67,11 +64,11 @@
|
|||
(define-language lang
|
||||
(a 1 2 3)
|
||||
(b a (a_1 b_!_1)))
|
||||
(let ([bc (find-base-cases/unparsed lang)])
|
||||
(let ([bc (find-base-cases lang)])
|
||||
(test (to-table (base-cases-non-cross bc))
|
||||
'((a . (0 0 0)) (b . (1 2))))
|
||||
(test (to-table (base-cases-cross bc))
|
||||
'((a-a . (0)) (a-b . (1)) (b-b . (0))))))
|
||||
'((a-a . (0)) (a-b . (1 2 2)) (b-b . (0 1))))))
|
||||
|
||||
(let ()
|
||||
(define-language lc
|
||||
|
@ -82,7 +79,7 @@
|
|||
(v (λ (x) e)
|
||||
number)
|
||||
(x variable))
|
||||
(let ([bc (find-base-cases/unparsed lc)])
|
||||
(let ([bc (find-base-cases lc)])
|
||||
(test (to-table (base-cases-non-cross bc))
|
||||
'((e . (2 2 1 1)) (v . (2 0)) (x . (0))))
|
||||
(test (to-table (base-cases-cross bc))
|
||||
|
@ -96,7 +93,7 @@
|
|||
(name x 1)
|
||||
(name y 1))
|
||||
(y y))
|
||||
(test (hash-ref (base-cases-non-cross (find-base-cases/unparsed L)) 'x)
|
||||
(test (hash-ref (base-cases-non-cross (find-base-cases L)) 'x)
|
||||
'(0 0 0 0)))
|
||||
|
||||
(define (make-random . nums)
|
||||
|
@ -325,7 +322,7 @@
|
|||
(test (generate-term/decisions lang d 5 0 (decisions #:seq (list (λ (_) 2))))
|
||||
'(4 4 4 4 (4 4) (4 4)))
|
||||
(test (raised-exn-msg exn:fail:redex:generation-failure? (generate-term lang e 5 #:retries 42))
|
||||
#rx"generate-term: unable to generate pattern \\(n_1 ..._!_1 n_2 ..._!_1 \\(n_1 n_2\\) ..._3\\) in 42")
|
||||
#rx"generate-term: unable to generate pattern .* in 42")
|
||||
(test (raised-exn-msg
|
||||
exn:fail:redex:generation-failure?
|
||||
(parameterize ([generation-decisions
|
||||
|
@ -340,7 +337,9 @@
|
|||
#rx"generate-term: unable to generate pattern variable-not-otherwise-mentioned in 1")
|
||||
(test (generate-term/decisions lang f 5 0 (decisions #:seq (list (λ (_) 0)))) null)
|
||||
(test (generate-term/decisions
|
||||
lang ((0 ..._!_1) ... (1 ..._!_1) ...) 5 0
|
||||
lang
|
||||
((0 ..._!_1) ... (1 ..._!_1) ...)
|
||||
5 0
|
||||
(decisions #:seq (list (λ (_) 2) (λ (_) 3) (λ (_) 4) (λ (_) 2) (λ (_) 3) (λ (_) 4)
|
||||
(λ (_) 2) (λ (_) 3) (λ (_) 4) (λ (_) 1) (λ (_) 3))))
|
||||
'((0 0 0) (0 0 0 0) (1 1 1)))
|
||||
|
@ -412,7 +411,7 @@
|
|||
(test (generate-term lang b 5) 43)
|
||||
(test (generate-term lang (side-condition a (odd? (term a))) 5) 43)
|
||||
(test (raised-exn-msg exn:fail:redex:generation-failure? (generate-term lang c 5))
|
||||
#px"unable to generate pattern \\(side-condition a\\_1 #<syntax:.*\\/rg-test\\.(?:.+):\\d+:\\d+>\\)")
|
||||
#rx"unable to generate pattern")
|
||||
(test (let/ec k
|
||||
(generate-term lang (number_1 (side-condition 7 (k (term number_1)))) 5))
|
||||
'number_1)
|
||||
|
@ -603,7 +602,7 @@
|
|||
(decisions #:nt (patterns first)))
|
||||
47)
|
||||
|
||||
(test (hash-ref (base-cases-non-cross (find-base-cases/unparsed name-collision)) 'e-e)
|
||||
(test (hash-ref (base-cases-non-cross (find-base-cases name-collision)) 'e-e)
|
||||
'(0)))
|
||||
|
||||
(let ()
|
||||
|
@ -1217,109 +1216,66 @@
|
|||
(check-metafunction n (λ (_) #t) #:retries 42))
|
||||
#rx"check-metafunction: unable .* in 42"))
|
||||
|
||||
;; parse/unparse-pattern
|
||||
(let-syntax ([test-match (syntax-rules () [(_ p x) (test (match x [p #t] [_ #f]) #t)])])
|
||||
(define-language lang (x variable))
|
||||
(let ([pattern '((x_1 number) ... 3)])
|
||||
(test-match (list
|
||||
(struct ellipsis
|
||||
('...
|
||||
(list (struct binder ('x_1)) (struct binder ('number)))
|
||||
_
|
||||
(list (struct binder ('number)) (struct binder ('x_1)))))
|
||||
3)
|
||||
(parse-pattern pattern lang 'top-level))
|
||||
(test (unparse-pattern (parse-pattern pattern lang 'top-level)) pattern))
|
||||
(let ([pattern '((x_1 ..._1 x_2) ..._!_1)])
|
||||
(test-match (struct ellipsis
|
||||
((struct mismatch (i_1 '..._!_1))
|
||||
(list
|
||||
(struct ellipsis
|
||||
('..._1
|
||||
(struct binder ('x_1))
|
||||
(struct class ('..._1))
|
||||
(list (struct binder ('x_1)))))
|
||||
(struct binder ('x_2)))
|
||||
_
|
||||
(list (struct binder ('x_2)) '..._1 (struct class ('..._1)) (struct binder ('x_1)))))
|
||||
(car (parse-pattern pattern lang 'grammar)))
|
||||
(test (unparse-pattern (parse-pattern pattern lang 'grammar)) pattern))
|
||||
(let ([pattern '((name x_1 x_!_2) ...)])
|
||||
(test-match (struct ellipsis
|
||||
('... `(name x_1 ,(struct mismatch (i_2 'x_!_2))) _
|
||||
(list (struct binder ('x_1)) (struct mismatch (i_2 'x_!_2)))))
|
||||
(car (parse-pattern pattern lang 'grammar)))
|
||||
(test (unparse-pattern (parse-pattern pattern lang 'grammar)) pattern))
|
||||
(let ([pattern '((x ...) ..._1)])
|
||||
(test-match (struct ellipsis
|
||||
('..._1
|
||||
(list
|
||||
(struct ellipsis
|
||||
('...
|
||||
(struct binder ('x))
|
||||
(struct class (c_1))
|
||||
(list (struct binder ('x))))))
|
||||
_
|
||||
(list (struct class (c_1)) (struct binder ('x)))))
|
||||
(car (parse-pattern pattern lang 'top-level)))
|
||||
(test (unparse-pattern (parse-pattern pattern lang 'top-level)) pattern))
|
||||
(let ([pattern '((variable_1 ..._!_1) ...)])
|
||||
(test-match (struct ellipsis
|
||||
('...
|
||||
(list
|
||||
(struct ellipsis
|
||||
((struct mismatch (i_1 '..._!_1))
|
||||
(struct binder ('variable_1))
|
||||
(struct class (c_1))
|
||||
(list (struct binder ('variable_1))))))
|
||||
_
|
||||
(list (struct class (c_1)) (struct mismatch (i_1 '..._!_1)) (struct binder ('variable_1)))))
|
||||
(car (parse-pattern pattern lang 'grammar)))
|
||||
(test (unparse-pattern (parse-pattern pattern lang 'grammar)) pattern))
|
||||
(test (parse-pattern '(cross x) lang 'grammar) '(cross x-x))
|
||||
(test (parse-pattern '(cross x) lang 'cross) '(cross x))
|
||||
(test (parse-pattern 'x lang 'grammar) 'x)
|
||||
(test (parse-pattern 'variable lang 'grammar) 'variable))
|
||||
|
||||
(let ()
|
||||
(define-language lang (x variable))
|
||||
(define-syntax test-class-reassignments
|
||||
(syntax-rules ()
|
||||
[(_ pattern expected)
|
||||
(test (to-table (class-reassignments (parse-pattern pattern lang 'top-level)))
|
||||
(test (to-table (class-reassignments pattern))
|
||||
expected)]))
|
||||
|
||||
(test-class-reassignments
|
||||
'(x_1 ..._1 x_2 ..._2 x_2 ..._1)
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f) (repeat (name x_2 (nt x)) ..._2 #f) (repeat (name x_2 (nt x)) ..._1 #f))
|
||||
'((..._2 . ..._1)))
|
||||
(test-class-reassignments
|
||||
'((x_1 ..._1 x_1 ..._2) (x_2 ..._1 x_2 ..._2) x_3 ..._2)
|
||||
'(list (list (repeat (name x_1 (nt x)) ..._1 #f) (repeat (name x_1 (nt x)) ..._2 #f))
|
||||
(list (repeat (name x_2 (nt x)) ..._1 #f) (repeat (name x_2 (nt x)) ..._2 #f))
|
||||
(repeat (name x_3 (nt x)) ..._2 #f))
|
||||
'((..._1 . ..._2) (..._2 . ..._2)))
|
||||
(test-class-reassignments
|
||||
'(x_1 ..._1 x ..._2 x_1 ..._2)
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f) (repeat (name x (nt x)) ..._2 #f) (repeat (name x_1 (nt x)) ..._2 #f))
|
||||
'((..._1 . ..._2)))
|
||||
(test-class-reassignments
|
||||
'(x_1 ..._1 x_2 ..._2 (x_1 x_2) ..._3)
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f) (repeat (name x_2 (nt x)) ..._2 #f) (repeat (list (name x_1 (nt x)) (name x_2 (nt x))) ..._3 #f))
|
||||
'((..._1 . ..._3) (..._2 . ..._3)))
|
||||
(test-class-reassignments
|
||||
'((x_1 ..._1) ..._2 x_2 ..._3 (x_1 ..._4 x_2) ..._5)
|
||||
'(list (repeat (list (repeat (name x_1 (nt x)) ..._1 #f)) ..._2 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._4 #f)
|
||||
(name x_2 (nt x)))
|
||||
..._5
|
||||
#f))
|
||||
'((..._1 . ..._4) (..._2 . ..._5) (..._3 . ..._5)))
|
||||
(test-class-reassignments
|
||||
'((x_1 ..._1) ..._2 (x_1 ..._3) ..._4 (x_1 ..._5) ..._6)
|
||||
'(list (repeat (list (repeat (name x_1 (nt x)) ..._1 #f)) ..._2 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._3 #f)) ..._4 #f)
|
||||
(repeat (list (repeat (name x_1 (nt x)) ..._5 #f)) ..._6 #f))
|
||||
'((..._1 . ..._5) (..._2 . ..._6) (..._3 . ..._5) (..._4 . ..._6)))
|
||||
(test-class-reassignments
|
||||
'(x_1 ..._1 x_1 ..._2 x_2 ..._1 x_2 ..._4 x_2 ..._3)
|
||||
'(list (repeat (name x_1 (nt x)) ..._1 #f)
|
||||
(repeat (name x_1 (nt x)) ..._2 #f)
|
||||
(repeat (name x_2 (nt x)) ..._1 #f)
|
||||
(repeat (name x_2 (nt x)) ..._4 #f)
|
||||
(repeat (name x_2 (nt x)) ..._3 #f))
|
||||
'((..._1 . ..._3) (..._2 . ..._3) (..._4 . ..._3)))
|
||||
(test
|
||||
(hash-map
|
||||
(class-reassignments (parse-pattern '(x_1 ... x_1 ..._!_1 x_1 ..._1) lang 'top-level))
|
||||
(class-reassignments '(list (repeat (name x_1 (nt x)) #f #f)
|
||||
(repeat (name x_1 (nt x)) ..._!_1 #t)
|
||||
(repeat (name x_1 (nt x)) ..._1 #f)))
|
||||
(λ (_ cls) cls))
|
||||
'(..._1 ..._1))
|
||||
'(..._1 ..._1))
|
||||
(test-class-reassignments
|
||||
'((3 ..._1) ..._2 (4 ..._1) ..._3)
|
||||
'(list (repeat (list (repeat 3 ..._1 #f)) ..._2 #f)
|
||||
(repeat (list (repeat 4 ..._1 #f)) ..._3 #f))
|
||||
'((..._2 . ..._3)))
|
||||
(test-class-reassignments
|
||||
'(x ..._1 x ..._2 variable ..._2 variable ..._3 variable_1 ..._3 variable_1 ..._4)
|
||||
'(list (repeat (name x (nt x)) ..._1 #f)
|
||||
(repeat (name x (nt x)) ..._2 #f)
|
||||
(repeat (name variable variable) ..._2 #f)
|
||||
(repeat (name variable variable) ..._3 #f)
|
||||
(repeat (name variable_1 variable) ..._3 #f)
|
||||
(repeat (name variable_1 variable) ..._4 #f))
|
||||
'((..._1 . ..._4) (..._2 . ..._4) (..._3 . ..._4))))
|
||||
|
||||
;; redex-test-seed
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
(append
|
||||
'("lw-test.rkt"
|
||||
"matcher-test.rkt"
|
||||
"rewrite-side-condition-test.rkt"
|
||||
"tl-test.rkt"
|
||||
"term-test.rkt"
|
||||
"rg-test.rkt"
|
||||
|
@ -34,6 +35,7 @@
|
|||
'("../examples/cbn-letrec.rkt"
|
||||
"../examples/stlc.rkt"
|
||||
"../examples/pi-calculus.rkt"
|
||||
"../examples/list-machine/test.rkt"
|
||||
("../examples/beginner.rkt" main)
|
||||
"../examples/racket-machine/reduction-test.rkt"
|
||||
"../examples/racket-machine/verification-test.rkt"
|
||||
|
|
|
@ -171,8 +171,8 @@
|
|||
(let ()
|
||||
(define-judgment-form syn-err-lang
|
||||
#:mode (pat-depth I O)
|
||||
[(pat-depth (binder2 ellipsis) ())
|
||||
(pat-depth () binder1)])
|
||||
[(pat-depth (binder1 ellipsis) ())
|
||||
(pat-depth () binder2)])
|
||||
(void)))
|
||||
(#rx"too many ellipses"
|
||||
([premise (no-ellipsis any)])
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
|
||||
(#rx"different depths"
|
||||
([binder2 number_1] [binder1 number_1]) ([ellipsis ...])
|
||||
([binder1 number_1] [binder2 number_1]) ([ellipsis ...])
|
||||
(reduction-relation
|
||||
syn-err-lang
|
||||
(--> binder1
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
(define-syntax (test stx)
|
||||
(syntax-case stx ()
|
||||
[(_ expected got)
|
||||
(with-syntax ([line (syntax-line (syntax got))]
|
||||
(with-syntax ([line (syntax-line stx)]
|
||||
[fn (if (path? (syntax-source (syntax got)))
|
||||
(path->string (syntax-source (syntax got)))
|
||||
"<unknown file>")])
|
||||
|
@ -142,7 +142,7 @@
|
|||
(matches? got expected))
|
||||
(set! failures (+ 1 failures))
|
||||
(fprintf (current-error-port)
|
||||
"test/proc: file ~a line ~a:\n got ~s\nexpected ~s\n\n"
|
||||
"test: file ~a line ~a:\n got ~s\nexpected ~s\n\n"
|
||||
filename
|
||||
line
|
||||
got
|
||||
|
|
|
@ -2533,7 +2533,7 @@
|
|||
; test that names are properly bound for side-conditions in shortcuts
|
||||
(let* ([lhs ((rewrite-proc-lhs (first (reduction-relation-make-procs r))) grammar)]
|
||||
[proc (third lhs)]
|
||||
[name (cadadr lhs)]
|
||||
[name (cadar (cddadr lhs))]
|
||||
[bind (λ (n) (make-bindings (list (make-bind name n))))])
|
||||
(test (and (proc (bind 4)) (not (proc (bind 3)))) #t))
|
||||
|
||||
|
@ -2551,7 +2551,7 @@
|
|||
|
||||
; test shortcut in terms of shortcut
|
||||
(test (match ((rewrite-proc-lhs (third (reduction-relation-make-procs r))) grammar)
|
||||
[`(((side-condition 5 ,(? procedure?) ,_) 2) 1) #t]
|
||||
[`(list (list (side-condition 5 ,(? procedure?) ,_) 2) 1) #t]
|
||||
[else #f])
|
||||
#t))
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user