racket/collects/redex/private/compiler/redextomatrix.rkt
2010-09-08 14:12:47 -05:00

615 lines
22 KiB
Racket
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#lang racket
(require redex)
(require "match.rkt")
(require racket/set)
(require profile)
(provide test-red-rel
test-non-term)
(define lit-table (make-hash))
(define or-table (make-hash))
(define nt-table (make-hash))
(define set-from-list
(λ (lst)
(apply set lst)))
(define-struct nt-struct (match-bool match-set))
#;(define lang '(define-language T
(n (number_1 ... number_1 ...))
(m ((number_1 number_1) ...))
(o ((number_1 ... number_1 ...) ...))
(q ((number_1 ... number_1 ...) ... (number_1 ... number_1 ...) ...))
))
#;(define lang '(define-language T
(e (e e ...) (if0 e e e) x v)
(v (λ (x ...) e) number * +)
(E (v ... E e ...) (if0 E e e) hole)
(x (variable-except if0 λ * +)))
)
#;(define lang-rr
'(reduction-relation T
(--> (in-hole C (and false B))
(in-hole C false)
)
(--> (in-hole C (and true B))
(in-hole C B)
)
(--> (in-hole C (or false B))
(in-hole C B))
(--> (in-hole C (or true B))
(in-hole C true))
))
#;(define-metafunction λv
subst-vars : ((x any) ... any) -> any
[(subst-vars ((x_1 any_1) x_1)) any_1]
[(subst-vars ((x_1 any_1) (any_2 ...)))
((subst-vars ((x_1 any_1) any_2)) ...)]
[(subst-vars (side-condition
((x_1 any_1) any_2)
(not (eq? (term x_1) (term any_2)))))
any_2]
[(subst-vars ((x_1 any_1) (x_2 any_2) ... any_3))
(subst-vars ((x_1 any_1) (subst-vars ((x_2 any_2) ... any_3))))]
[(subst-vars (any)) any])
(define lang-rr
'(reduction-relation
λv
(--> ((x_1 any_1) x_1)
any_1)
(--> ((x_1 any_1) (any_2 ...))
,(map subst-vars (term (((x_1 any_1) any_2) ...))) )
(--> (side-condition
((x_1 any_1) any_2)
(and (not (list? any_2))
(not (eq? (term x_1) (term any_2)))))
any_2)
(--> ((x_1 any_1) (x_2 any_2) (x_3 any_3) ... any_4)
,(subst-vars (term ((x_1 any_1) ,(subst-vars (term ((x_2 any_2) (x_3 any_3) ... any_4)))))))
(--> (any)
any)
)
)
#;(define-metafunction λv
subst : (x any any) -> any
;; 1. x_1 bound, so don't continue in λ body
[(subst (x_1 any_1 (λ (x_2 ... x_1 x_3 ...) any_2)))
(λ (x_2 ... x_1 x_3 ...) any_2)]
;; 2. general purpose capture avoiding case
[(subst (side-condition
(x_1 any_1 (λ (x_2 ...) any_2))
(not (memq (term x_1) (term (x_2 ...))))))
,(term-let ([(x_new ...) (variables-not-in (term (x_1 any_1 any_2)) (term (x_2 ...)))])
(term
(λ (x_new ...) (subst (x_1 any_1 (subst-vars ((x_2 x_new) ... any_2)))))))]
;; 3. replace x_1 with e_1
[(subst (x_1 any_1 x_1)) any_1]
;; 4. x_1 and x_2 are different, so don't replace
[(subst (side-condition
(x_1 any_1 x_2)
(not (eq? (term x_1) (term x_2)))))
x_2]
;; the last cases cover all other expressions
[(subst (x any (e_1 e_2 ...)))
(,(subst (x any e_1)) (subst (x any e_2)) ...)]
[(subst (x any (if0 e_1 e_2 e_3)))
(if0 (subst (x any e_1)) (subst (x any e_2)) (subst (x any e_3)))]
[(subst (x any number)) number]
[(subst (x any +)) +]
[(subst (x any *)) *])
#;(define lang-rr
'(reduction-relation
λv
(--> (x_1 any_1 (λ (x_2 ... x_1 x_3 ...) any_2))
(λ (x_2 ... x_1 x_3 ...) any_2))
(--> (side-condition
(x_1 any_1 (λ (x_2 ...) any_2))
(not (memq (term x_1) (term (x_2 ...)))))
,(term-let ([(x_new ...) (variables-not-in (term (x_1 any_1 any_2)) (term (x_2 ...)))])
(term
(λ (x_new ...) ,(subst (term (x_1 any_1 ,(subst-vars (term ((x_2 x_new) ... any_2))))) )))) )
(--> (x_1 any_1 x_1)
any_1)
(--> (side-condition
(x_1 any_1 x_2)
(not (eq? (term x_1) (term x_2))))
x_2)
(--> (x any (e_1 e_2 ...))
(,(subst (term (x any e_1))) ,@(map subst (term ((x any e_2) ...)))) )
(--> (x any (if0 e_1 e_2 e_3))
(if0 ,(subst (term (x any e_1))) ,(subst (term (x any e_2))) ,(subst (term (x any e_3)))))
(--> (x any number)
number)
(--> (x any +)
+)
(--> (x any *)
*)
)
)
#;(define-metafunction λv
subst-n : ((x any) ... any) -> any
[(subst-n ((x_1 any_1) (x_2 any_2) ... any_3))
(subst (x_1 any_1 (subst-n (x_2 any_2) ... any_3)))]
[(subst-n (any_3)) any_3])
#;(define lang-rr '(reduction-relation
λv
(--> ((x_1 any_1) (x_2 any_2) ... any_3)
,(subst (term (x_1 any_1 ,(subst-n (term ((x_2 any_2) ... any_3)))))))
(--> (any_3)
any_3)
)
)
#;(define lang-rr '(reduction-relation
λv
(--> (in-hole E (* number_1 number_2))
(in-hole E ,(* (term number_1) (term number_2))))
(--> (in-hole E (+ number_1 number_2))
(in-hole E ,(+ (term number_1) (term number_2))))
(--> (in-hole E (if0 0 e_1 e_2))
(in-hole E e_1))
(--> (in-hole E (if0 (side-condition number_1 (not (zero? (term number_1)))) e_1 e_2))
(in-hole E e_2))
(--> (in-hole E (side-condition ((λ (x ...) e) v ...)
(= (length (term (x ...)))
(length (term (v ...))))))
(in-hole E ,(subst-n (term ((x v) ... e))))))
)
(define (compile-define-language-nts dl)
(match dl
[`(define-language ,(? symbol? name)
,non-terms ...)
(map (λ (x) (car x))
non-terms)]
[_
'error]))
(define (compile-define-language-lit dl nts)
(match dl
[`(define-language ,(? symbol? name)
,non-terms ...)
(map (λ (x) (extract-literals/pat nts (cdr x) lit-table))
non-terms)]
[_
'error]))
(define (extract-literals/pat nts pat ht)
(let loop ([pat pat])
(match pat
[`any (void)]
[`number (void)]
[`string (void)]
[`natural (void)]
[`integer (void)]
[`real (void)]
[`variable (void)]
[`(variable-except ,s ...) (void)]
[`(variable-prefix ,s) (void)]
[`variable-not-otherwise-mentioned (void)]
[`hole (void)]
[(? symbol? s)
(unless (regexp-match #rx"_" (symbol->string s))
(unless (regexp-match #rx"^\\.\\.\\." (symbol->string s))
(unless (memq s nts)
(hash-set! ht s #t)
)))]
[`(name ,name ,pat) (loop pat)]
[`(in-hole ,p1 ,p2)
(loop p1)
(loop p2)]
[`(hide-hole ,p) (loop p)]
[`(side-condition ,p ,g ,e)
(loop p)]
[`(cross ,s) (void)]
[_
(let l-loop ([l-pat pat])
(when (pair? l-pat)
(loop (car l-pat))
(l-loop (cdr l-pat))))])))
(define (compile-define-language-or dl nts)
(match dl
[`(define-language ,(? symbol? name)
,non-terms ...)
(map (λ (x) (hash-set! or-table (car x) (build-or (cdr x) nts (hash-map lit-table (λ (x y) x)) #t)))
non-terms)]
[_
'error]))
(define (build-or pat-l nts syms dl)
(let loop ([pat-l pat-l]
[nts nts]
[syms syms])
(if (pair? pat-l)
(if (eqv? (length pat-l) 1)
(translate-redex (car pat-l) nts syms dl)
`(or ,(translate-redex (car pat-l) nts syms dl)
,(loop (cdr pat-l) nts syms)))
(translate-redex pat-l nts syms dl))))
(define (translate-redex pat nts syms dl)
(let loop ([pat pat])
(match pat
[`(,repeated ,(? (λ (x) (eq? x '...)) ep))
`(repeat ,(loop repeated) '())]
[`(,repeated ,(? (λ (x) (eq? x '...)) ep) ,next ...)
`(repeat ,(loop repeated) ,(loop next))]
[`any (if dl 'wc '(lit-name any wc))]
[`number (if dl 'lit-number '(lit-name number lit-number))]
[`string (if dl 'lit-string '(lit-name string lit-string))]
[`natural (if dl 'lit-natural '(lit-name natural lit-natural))]
[`integer (if dl 'lit-integer '(lit-name integer lit-integer))]
[`real (if dl 'lit-real '(lit-name real lit-real))]
[`variable (if dl 'lit-variable '(lit-name variable lit-variable))]
[`(variable-except ,s ...) `(lit-variable-except ,@s)]
[`(variable-prefix ,s) `(lit-variable-prefix ,s)]
[`variable-not-otherwise-mentioned (if dl `(lit-variable-except ,@syms) `(lit-name variable-not-otherwise-mentioned (lit-variable-except ,@syms)))]
[`hole 'lit-hole]
; for now if it has an underscore assume it's a non-terminal
[(? symbol? s)
(if (memq s nts)
(if dl
`(nt ,s)
`(lit-name ,s (nt ,s)))
(if (has-underscore? s)
(let ((split (split-underscore s)))
(cond
((equal? split 'any) `(lit-name ,s wc))
((equal? split 'number) `(lit-name ,s lit-number))
((equal? split 'string) `(lit-name ,s lit-string))
((equal? split 'natural) `(lit-name ,s lit-natural))
((equal? split 'integer) `(lit-name ,s lit-integer))
((equal? split 'real) `(lit-name ,s lit-real))
((equal? split 'variable) `(lit-name ,s lit-variable))
((equal? split 'variable-not-otherwise-mentioned) `(lit-name ,s (lit-variable-except ,@syms)))
((equal? split 'hole) `(lit-name ,s lit-hole))
(else `(lit-name ,s (nt ,split)))
)
)
`',s))]
[`(name ,name ,pat) `(lit-name ,name ,(loop pat))]
[`(in-hole ,p1 ,p2)
`(lit-in-hole
,(loop p1)
,(loop p2))]
[`(hide-hole ,p) `(lit-hide-hole ,(loop p))]
[`(side-condition ,p #;,g ,e)
`(lit-side-condition ,(loop p) ,e)]
[`(cross ,s) (void)]
[e
(if (pair? pat)
`(cons ,(loop (car pat))
,(loop (cdr pat)))
(if (empty? pat)
''()
e))]
)))
;; split-underscore : symbol -> symbol
;; returns the text before the underscore in a symbol (as a symbol)
;; raise an error if there is more than one underscore in the input
(define (split-underscore sym)
(let ([str (symbol->string sym)])
(cond
[(regexp-match #rx"^([^_]*)_[^_]*$" str)
=>
(λ (m) (string->symbol (cadr m)))]
[(regexp-match #rx"^([^_]*)_!_[^_]*$" str)
=>
(λ (m) (string->symbol (cadr m)))]
[else
(error 'compile-pattern "found a symbol with multiple underscores: ~s" sym)])))
;; has-underscore? : symbol -> boolean
(define (has-underscore? sym)
(memq #\_ (string->list (symbol->string sym))))
(define build-hole-table
(λ (old-ht)
(unless (equal? hole-table old-ht)
(let ((prev (make-hash)))
(hash-for-each
hole-table
(λ (key val)
(hash-set! prev key val)))
(hash-for-each
or-table
(λ (key val)
;(printf "~a: ~a\n" key `(term (detect-hole2 0 ,val)))
(hash-set! hole-table key (term (detect-hole2 0 ,val)))))
(build-hole-table prev))))
)
(define state '())
(define hole-var '())
(define nt-func '())
(define wrap-production-with-name
(λ (x)
(set! state x)
(set! hole-var '())
(set! nt-func '())
(wrap-production-with-name-helper x)
)
)
(define wrap-production-with-name-helper
(λ (exp)
(match exp
[`(cons ,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p1)
,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p2))
`(cons ,(wrap-production-with-name-helper p1) ,(wrap-production-with-name-helper p2))]
[`(cons ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p1)
,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p2))
`(cons ,(wrap-production-with-name-helper p1) ,(wrap-production-with-name-helper p2))]
[`(cons ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p1)
,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p2))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x (cons ,p1 ,p2)))]
[`(lit-name ,id ,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p))
`(lit-name ,id ,(wrap-production-with-name-helper p))]
[`(lit-name ,id ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p))
`(lit-name ,id ,p)]
[`(lit-side-condition ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p) ,any)
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x (lit-side-condition ,p ,any))
)]
[`(lit-side-condition ,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p) ,any)
(wrap-production-with-name-helper p)]
[`(repeat ,p1 ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p2))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x (repeat ,p1 ,p2))
)]
[`(repeat ,p1 ,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p2))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(repeat (lit-name ,x ,p1) ,(wrap-production-with-name-helper p2))
)]
[`(lit-in-hole ,p1 ,(? (λ (x) (eqv? 0 (term (detect-hole2 0 ,x)))) p2))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x (lit-in-hole ,p1 ,p2))
)]
[`(lit-in-hole ,p1 ,(? (λ (x) (eqv? 1 (term (detect-hole2 0 ,x)))) p2))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
(let ((y (variable-not-in state 'y)))
(set! hole-var y)
`(lit-in-hole (lit-name ,x ,p1) (lit-name ,y ,p2))
)
)]
['lit-hole
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
(set! hole-var x)
`(lit-name ,x lit-hole)
)]
[`(nt ,id)
(if (eqv? 1 (term (detect-hole2 0 (nt ,id))))
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
(set! hole-var x)
(set! nt-func id)
`(lit-name ,x wc)
)
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x (nt ,id))
)
)]
[`',(? (λ (x) (or (symbol? x) (equal? '() x))) ex)
exp]
[_ (if (or (number? exp) (string? exp) (boolean? exp))
exp
(let ((x (variable-not-in state 'x)))
(set! state (cons x state))
`(lit-name ,x ,exp)
))])
)
)
(define build-right-hand-side
(λ (x)
(if (equal? nt-func '())
(if (equal? hole-var '())
`(set! results (cons (cons ,(build-right-hand-side-helper x) '()) results))
`(set! results (cons (cons ,(build-right-hand-side-helper x) (term ,hole-var)) results))
)
`(for ((,hole-var (in-list (,(string->symbol (format "~s~s" nt-func '-list)) (term ,hole-var)))))
(set! results (cons (cons ,(build-right-hand-side-helper x) (cdr ,hole-var)) results))
)
)
)
)
(define build-right-hand-side-helper
(λ (exp)
(match exp
[`(lit-name ,(? (λ (x) (not (equal? hole-var x))) x) ,p)
(if (or (not (cons? p)) (and (cons? p) (not (equal? (car p) 'lit-name))))
`(term ,x)
(build-right-hand-side-helper p))]
[`(lit-name ,(? (λ (x) (equal? hole-var x)) x) lit-hole)
'the-hole]
[`(lit-name ,(? (λ (x) (equal? hole-var x)) x) wc)
`(car ,hole-var)]
[`(lit-name ,(? (λ (x) (equal? hole-var x)) x) ,p)
`(term ,x)]
[`(cons ,p1 ,p2)
`(cons ,(build-right-hand-side-helper p1) ,(build-right-hand-side-helper p2))]
[`(lit-in-hole ,p1 ,p2)
(build-right-hand-side-helper p1)]
[`(repeat ,p1 ,p2)
`(append ,(build-right-hand-side-helper p1) ,(build-right-hand-side-helper p2))]
[_
exp]
)))
(define make-or-list
(λ (exp)
(match exp
[`(or ,pro1 ,pro2)
(cons pro1 (make-or-list pro2))]
[_ (cons exp '())]
)
)
)
(define-namespace-anchor here)
;; compile-dl : sexp[lang] -> (listof sexp[def])
(define (compile-dl lang)
(let* ([lang lang]
[nts (compile-define-language-nts lang)]
[lit-table lit-table]
[or-table or-table]
[nt-table nt-table]
[hole-table hole-table])
(compile-define-language-lit lang nts)
(compile-define-language-or lang nts)
(caching-enabled? #f)
; Initialize the hole table
(hash-for-each
or-table
(λ (key val)
(hash-set! hole-table key (term (detect-hole 0 ,val)))
))
(build-hole-table '())
(caching-enabled? #t)
(hash-for-each
or-table
(λ (key val)
(let ((compiled-bool (car (apply-reduction-relation* red
(term (matrix (a)
(
((,val -> (set! results (cons #t results))) ,@(map (λ (x) (list x #f)) (remove-duplicates (term (Get-Free-Name-Patterns ,val () ())))))
)
()
()
0
#f)))))
(compiled-set (car (apply-reduction-relation* red
(term (matrix (a)
( ,@(map (λ (x)
(let ((row (wrap-production-with-name x)))
`((,row -> ,(build-right-hand-side row))
,@(map (λ (x) (list x #f)) (remove-duplicates (term (Get-Free-Name-Patterns ,row () ())))))))
(make-or-list val)))
()
()
0
#f))))
))
(hash-set! nt-table
key
(make-nt-struct
(term (define ,(string->symbol (format "~s~s" key '-bool))
(λ (a)
(let ((results (list)))
,compiled-bool
(and (andmap values results) (positive? (length results)))))))
(term (define ,(string->symbol (format "~s~s" key '-list))
(λ (a)
(let ((results (list)))
,compiled-set
results)))))))))
(append (hash-map nt-table (λ (_ n) (nt-struct-match-bool n)))
(hash-map nt-table (λ (_ n) (nt-struct-match-set n))))))
; compile-reduction-relation: sexp[reduction-relation] (listof symbol[non-terminals]) (listof symbols) -> sexp[def]
(define (compile-reduction-relation rr nts syms)
`(λ (a)
(let ([results '()])
,(car
(apply-reduction-relation*
red
(let loop ([e rr])
(match e
[`(reduction-relation ,L ,rules ...)
(term (matrix (a) ,(map loop rules) () () 0 #f))]
[`(--> ,pat ,t)
(let ((p (translate-redex pat nts syms #f)))
`((,p -> (set! results (cons (term ,t) results)))
,@(map (λ (x) (list x #f))
(remove-duplicates (term (Get-Free-Name-Patterns ,p () ()))))))]))))
results)))
;; make-lang-namespace: sexp[lang] -> namespace
(define (make-lang-namespace lang)
(define lang-defs (compile-dl lang))
(define namespace (namespace-anchor->namespace here))
(for-each (curryr eval namespace) lang-defs)
namespace)
;; test-red-rel: sexp[lang] -> sexp[red-rel] (listof sexp[nts]) (listof symbol) -> sexp[term] -> sexp[term]
(define (test-red-rel lang)
(define namespace (make-lang-namespace lang))
(λ (rel nts syms)
(eval (compile-reduction-relation rel nts syms) namespace)))
;; sexp[lang] -> sexp[non-terminal] -> sexp[term] -> boolean
(define (test-non-term lang)
(define namespace (make-lang-namespace lang))
(λ (nt)
(eval `(λ (t) (,(string->symbol (format "~s-bool" nt)) t)) namespace)))
(define-language T
(B true
false
(and B B))
(C (and C B)
hole))
(define bool-red-test
(reduction-relation T
(--> (in-hole C (and false B))
(in-hole C false)
)
(--> (in-hole C (and true B))
(in-hole C B)
)))
(caching-enabled? #f)
(define #f)
(define set-union)
(define singleton set)
(define no-context #f)
(define in-context #t)
(define context-match (make-parameter no-context))
(define rev (λ (x)
(if (cons? x)
(reverse x)
x)))
(define or-fun (λ (x ...) (or x ...)))
(define sing-fun (λ (x) #t))
(define the-hole (term hole))