Changed `define-union-language' to merge nonterminals and their

right-hand-sides instead of causing an error when more than one language
in the union defines the same nonterminal.
This commit is contained in:
William J. Bowman 2013-02-28 13:45:50 -05:00 committed by Robby Findler
parent 32774924e2
commit b0db8798b6
3 changed files with 72 additions and 15 deletions

View File

@ -0,0 +1,40 @@
#lang racket
(provide LBase L1 L2 LMergeUntagged LMergeTagged)
(require redex/reduction-semantics)
;; ------------------------------------------------------------------------
(define-language LBase
(e (+ e e) number))
(define-extended-language L1 LBase
(e .... (- e e)))
(define-extended-language L2 LBase
(e .... (* e e)))
;; Untagged union of two languages that define the same nonterminal
(define-union-language LMergeUntagged L1 L2)
;; Tagged merge of two extended languages that define the same
;; nonterminal
(define-union-language LMergeTagged (f. L1) (d. L2))
;; ------------------------------------------------------------------------
(module+ test
(for ([t (list (term 1) (term (* 1 1)) (term (+ 1 1)) (term (- 1 1)))])
(test-equal (redex-match? LMergeUntagged e t) #t))
(test-equal (redex-match? LMergeTagged f.e 1) #t)
(test-equal (redex-match? LMergeTagged d.e 1) #t)
(test-equal (redex-match? LMergeTagged f.e (term (+ 1 1))) #t)
(test-equal (redex-match? LMergeTagged f.e (term (- 1 1))) #t)
(test-equal (redex-match? LMergeTagged f.e (term (* 1 1))) #f)
(test-equal (redex-match? LMergeTagged d.e (term (+ 1 1))) #t)
(test-equal (redex-match? LMergeTagged d.e (term (* 1 1))) #t)
(test-equal (redex-match? LMergeTagged d.e (term (- 1 1))) #f))

View File

@ -1911,10 +1911,10 @@
"malformed additional language"
stx orig-lang)])))
;; ht : sym -o> stx
;; ht : sym -o> (listof stx)
;; maps each non-terminal (with its prefix) to the
;; syntax object that it comes from in the original
;; define-union-language declaration
;; list syntax object that they comes from in the original
;; define-union-language declaration
(define names-table (make-hash))
(for ([normalized-orig-lang (in-list normalized-orig-langs)])
@ -1922,14 +1922,9 @@
(for ([no-prefix-nt (in-list (list-ref normalized-orig-lang 2))])
(define nt (string->symbol (string-append prefix (symbol->string no-prefix-nt))))
(let ([prev (hash-ref names-table nt #f)])
(when prev
(raise-syntax-error 'define-union-language
(format "two sublanguages both contribute the non-terminal: ~a" nt)
#f
#f
(list prev
(list-ref normalized-orig-lang 3))))
(hash-set! names-table nt (list-ref normalized-orig-lang 3)))))
(if prev
(hash-set! names-table nt (cons (list-ref normalized-orig-lang 3) prev))
(hash-set! names-table nt (list (list-ref normalized-orig-lang 3)))))))
(with-syntax ([(all-names ...) (sort (hash-map names-table (λ (x y) x)) string<=? #:key symbol->string)]
[((prefix old-lang _1 _2) ...) normalized-orig-langs]
@ -1969,10 +1964,26 @@
(make-nt (string->symbol (string-append prefix (symbol->string (nt-name nt))))
(for/list ([rhs (in-list (nt-rhs nt))])
(make-rhs (prefix-nts prefix (rhs-pattern rhs)))))))))
;; Each language in the union might define the same nt, and might
;; even define the same rhs for the same nt, so merge them to get a
;; proper union.
;; NOTE: This could probably be done when defining new-nts to
;; eliminate a second pass over all the nts.
(define merge-nts
(let ()
(define names-table (make-hash))
(for/list ([nt (in-list new-nts)])
(let* ([name (nt-name nt)]
[prev (hash-ref names-table name #f)])
(if prev
(hash-set! names-table name (make-nt name (remove-duplicates (append (nt-rhs prev) (nt-rhs nt)))))
(hash-set! names-table name nt))))
(hash-map names-table (lambda (x y) y))))
(compile-language #f
new-nts
new-nt-map))
merge-nts
(remove-duplicates new-nt-map)))
;; find-primary-nt : symbol lang -> symbol or #f

View File

@ -448,8 +448,14 @@
(one. L1)
|#
(test (and (redex-match LMerge one.e (term (- 0 0))) #t) #t)
(test (and (redex-match LMerge two.e (term (* 0 0))) #t) #t))
(test (and (redex-match LMerge two.e (term (* 0 0))) #t) #t)
(define-union-language LMergeUntagged L1 L2)
(for ([t (list (term 1) (term (* 1 1)) (term (+ 1 1)) (term (- 1 1)))])
(test (redex-match? LMergeUntagged e t) #t)))
(let ()
(define-language UT