Fixed various typos/bug, added latex generation
This commit is contained in:
parent
448ee8a83a
commit
b13bf6471d
131
oll.rkt
131
oll.rkt
|
@ -4,7 +4,8 @@
|
||||||
;; TODO: Automagically create a parser from bnf grammar
|
;; TODO: Automagically create a parser from bnf grammar
|
||||||
(require "stdlib/sugar.rkt" "stdlib/nat.rkt" racket/trace)
|
(require "stdlib/sugar.rkt" "stdlib/nat.rkt" racket/trace)
|
||||||
|
|
||||||
(provide define-relation define-language var avar var-equal?)
|
(provide define-relation define-language var avar var-equal?
|
||||||
|
generate-coq #;(rename-out [oll-define-theorem define-theorem]))
|
||||||
|
|
||||||
(begin-for-syntax
|
(begin-for-syntax
|
||||||
(define-syntax-class dash
|
(define-syntax-class dash
|
||||||
|
@ -23,10 +24,22 @@
|
||||||
line:dash lab:id
|
line:dash lab:id
|
||||||
(name:id y* ...))
|
(name:id y* ...))
|
||||||
#:with rule #'(lab : (forall* d ...
|
#:with rule #'(lab : (forall* d ...
|
||||||
(->* x* ... (name y* ...)))))))
|
(->* x* ... (name y* ...))))
|
||||||
|
;; TODO: convert meta-vars such as e1 to e_1
|
||||||
|
#:attr latex (format "\\inferrule~n{~a}~n{~a}"
|
||||||
|
(string-trim
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([hyp (syntax->datum #'(x* ...))])
|
||||||
|
(format "~a~a \\+" str hyp))
|
||||||
|
" \\+"
|
||||||
|
#:left? #f)
|
||||||
|
(format "~a" (syntax->datum #'(name y* ...)))))))
|
||||||
(define-syntax (define-relation syn)
|
(define-syntax (define-relation syn)
|
||||||
(syntax-parse syn
|
(syntax-parse syn
|
||||||
[(_ (n:id types* ...) rules:inferrence-rule ...)
|
[(_ (n:id types* ...)
|
||||||
|
(~optional (~seq #:output-coq coq-file:str))
|
||||||
|
(~optional (~seq #:output-latex latex-file:str))
|
||||||
|
rules:inferrence-rule ...)
|
||||||
#:fail-unless (andmap (curry equal? (length (syntax->datum #'(types* ...))))
|
#:fail-unless (andmap (curry equal? (length (syntax->datum #'(types* ...))))
|
||||||
(map length (syntax->datum #'((rules.y* ...)
|
(map length (syntax->datum #'((rules.y* ...)
|
||||||
...))))
|
...))))
|
||||||
|
@ -34,8 +47,26 @@
|
||||||
#:fail-unless (andmap (curry equal? (syntax->datum #'n))
|
#:fail-unless (andmap (curry equal? (syntax->datum #'n))
|
||||||
(syntax->datum #'(rules.name ...)))
|
(syntax->datum #'(rules.name ...)))
|
||||||
"Mismatch between relation declared name and result of inference rule"
|
"Mismatch between relation declared name and result of inference rule"
|
||||||
#`(data n : (->* types* ... Type)
|
(let ([output #`(data n : (->* types* ... Type) rules.rule ...)])
|
||||||
rules.rule ...)]))
|
;; TODO: Pull this out into a separate function and test. Except
|
||||||
|
;; that might make using attritbutes more difficult.
|
||||||
|
(when (attribute latex-file)
|
||||||
|
(with-output-to-file (syntax->datum #'latex-file)
|
||||||
|
(thunk
|
||||||
|
(format "\\fbox{$~a$}$~n$\\begin{mathpar}~n~a~n\end{mathpar}$$"
|
||||||
|
(string-trim
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([rule (syntax->datum #'(rules.latex ...))])
|
||||||
|
(format "~a~a\\and~n" rule))
|
||||||
|
"\\and"
|
||||||
|
#:left? #f)))
|
||||||
|
#:exists 'append))
|
||||||
|
#`(begin
|
||||||
|
#,@(if (attribute coq-file)
|
||||||
|
#`((generate-coq #:file coq-file #:exists
|
||||||
|
'append #,output))
|
||||||
|
#'())
|
||||||
|
#,output))]))
|
||||||
|
|
||||||
(begin-for-syntax
|
(begin-for-syntax
|
||||||
(require racket/syntax)
|
(require racket/syntax)
|
||||||
|
@ -127,8 +158,55 @@
|
||||||
#`((data name* : Type . rhs*.clause)
|
#`((data name* : Type . rhs*.clause)
|
||||||
...)))))
|
...)))))
|
||||||
|
|
||||||
|
(begin-for-syntax
|
||||||
|
;; TODO: More clever use of syntax-parse would enable something akin to what
|
||||||
|
;; define-relation is doing---having attributes that contain the latex
|
||||||
|
;; code for each clause.
|
||||||
|
;; TODO: convert meta-vars such as e1 to e_1
|
||||||
|
(define (output-latex-bnf vars clauses)
|
||||||
|
(format "$$\\begin{array}{lrrl}~n~a~n\\end{array}$$"
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([clause (syntax->list clauses)])
|
||||||
|
(syntax-parse clause
|
||||||
|
#:datum-literals (::=)
|
||||||
|
[(type:id (nonterminal:id ...) ::= exprs ...)
|
||||||
|
(format "\\mbox{\\textit{~a}} & ~a & \\bnfdef & ~a\\\\~n"
|
||||||
|
(symbol->string (syntax->datum #'type))
|
||||||
|
(string-trim
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([nt (syntax->datum #'(nonterminal ...))])
|
||||||
|
(format "~a~a," str nt))
|
||||||
|
","
|
||||||
|
#:left? #f)
|
||||||
|
(string-trim
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([expr (syntax->datum #'(exprs ...))])
|
||||||
|
(format "~a~a \\bnfalt " str expr))
|
||||||
|
" \\bnfalt "
|
||||||
|
#:left? #f))]))))
|
||||||
|
(define (generate-latex-bnf file-name vars clauses)
|
||||||
|
(with-output-to-file file-name
|
||||||
|
(thunk (output-latex-bnf vars clauses))
|
||||||
|
#:exists 'append)))
|
||||||
|
(module+ test
|
||||||
|
(require "stdlib/sugar.rkt")
|
||||||
|
(begin-for-syntax
|
||||||
|
(require rackunit)
|
||||||
|
(check-equal?
|
||||||
|
(format "$$\\begin{array}{lrrl}~n~a~n\\end{array}$$"
|
||||||
|
(format "\\mbox{\\textit{term}} & e & \\bnfdef & (e1 e2) \\bnfalt (lambda (x) e)\\\\~n"))
|
||||||
|
(output-latex-bnf #'(x)
|
||||||
|
#'((term (e) ::= (e1 e2) (lambda (x) e)))))
|
||||||
|
(check-equal?
|
||||||
|
(format "$$\\begin{array}{lrrl}~n~a~n\\end{array}$$"
|
||||||
|
(format "\\mbox{\\textit{type}} & A,B,C & \\bnfdef & unit \\bnfalt (* A B) \\bnfalt (+ A C)\\\\~n"))
|
||||||
|
(output-latex-bnf #'(x)
|
||||||
|
#'((type (A B C) ::= unit (* A B) (+ A C)))))))
|
||||||
;; TODO: For better error messages, add context, rename some of these patterns. e.g.
|
;; TODO: For better error messages, add context, rename some of these patterns. e.g.
|
||||||
;; (type (meta-vars) ::= ?? )
|
;; (type (meta-vars) ::= ?? )
|
||||||
|
;; TODO: Extend define-language with syntax such as ....
|
||||||
|
;; (term (e) ::= (e1 e2) ((lambda (x) e)
|
||||||
|
; #:latex "(\\lambda ,x. ,e)"))
|
||||||
(define-syntax (define-language syn)
|
(define-syntax (define-language syn)
|
||||||
(syntax-parse syn
|
(syntax-parse syn
|
||||||
[(_ name:id (~do (lang-name #'name))
|
[(_ name:id (~do (lang-name #'name))
|
||||||
|
@ -137,8 +215,17 @@
|
||||||
(~do (nts (for/fold ([ht (nts)])
|
(~do (nts (for/fold ([ht (nts)])
|
||||||
([v (syntax->datum #'(x* ...))])
|
([v (syntax->datum #'(x* ...))])
|
||||||
(hash-set ht v (hash-ref ht 'var)))))))
|
(hash-set ht v (hash-ref ht 'var)))))))
|
||||||
|
(~optional (~seq #:output-coq coq-file:str))
|
||||||
|
(~optional (~seq #:output-latex latex-file:str))
|
||||||
. clause*:nt-clauses)
|
. clause*:nt-clauses)
|
||||||
#`(begin . clause*.defs)]))
|
(let ([output #`(begin . clause*.defs)])
|
||||||
|
(when (attribute latex-file)
|
||||||
|
(generate-latex-bnf (syntax->datum #'latex-file) #'vars #'clause*))
|
||||||
|
#`(begin
|
||||||
|
#,@(if (attribute coq-file)
|
||||||
|
#`((generate-coq #:file coq-file #:exists 'append #,output))
|
||||||
|
#'())
|
||||||
|
#,output))]))
|
||||||
|
|
||||||
(data var : Type (avar : (-> nat var)))
|
(data var : Type (avar : (-> nat var)))
|
||||||
|
|
||||||
|
@ -171,11 +258,16 @@
|
||||||
(string-replace str (symbol->string (first p))
|
(string-replace str (symbol->string (first p))
|
||||||
(symbol->string (second p))))))
|
(symbol->string (second p))))))
|
||||||
(define (output-coq syn)
|
(define (output-coq syn)
|
||||||
(syntax-parse (cur-expand syn #'define #'define-theorem #'qed)
|
(syntax-parse (cur-expand syn #'define #'define-theorem #'qed
|
||||||
|
#'begin)
|
||||||
;; TODO: Need to add these to a literal set and export it
|
;; TODO: Need to add these to a literal set and export it
|
||||||
;; Or, maybe overwrite syntax-parse
|
;; Or, maybe overwrite syntax-parse
|
||||||
#:literals (lambda forall data real-app case define-theorem
|
#:literals (lambda forall data real-app case define-theorem
|
||||||
define qed)
|
define qed begin)
|
||||||
|
[(begin e ...)
|
||||||
|
(for/fold ([str ""])
|
||||||
|
([e (syntax->list #'(e ...))])
|
||||||
|
(format "~a~n" (output-coq e)))]
|
||||||
[(define-theorem name prop)
|
[(define-theorem name prop)
|
||||||
(begin
|
(begin
|
||||||
(fprintf (current-error-port) "Warning: If theorem ~a is not followed by a proof using (qed ...), the resulting Coq code may be malformed.~n" (output-coq #'name))
|
(fprintf (current-error-port) "Warning: If theorem ~a is not followed by a proof using (qed ...), the resulting Coq code may be malformed.~n" (output-coq #'name))
|
||||||
|
@ -249,24 +341,27 @@
|
||||||
|
|
||||||
(define-syntax (generate-coq syn)
|
(define-syntax (generate-coq syn)
|
||||||
(syntax-parse syn
|
(syntax-parse syn
|
||||||
[(_ (~optional (~seq #:file file)) body:expr)
|
[(_ (~optional (~seq #:file file))
|
||||||
|
(~optional (~seq #:exists flag)) body:expr)
|
||||||
(parameterize ([current-output-port (if (attribute file)
|
(parameterize ([current-output-port (if (attribute file)
|
||||||
(open-output-file (syntax->datum #'file)
|
(open-output-file (syntax->datum #'file)
|
||||||
#:exists 'replace)
|
#:exists
|
||||||
|
(if (attribute flag)
|
||||||
|
;; TODO: AHH WHAT?
|
||||||
|
(eval (syntax->datum #'flag))
|
||||||
|
'error))
|
||||||
(current-output-port))]
|
(current-output-port))]
|
||||||
[coq-defns ""])
|
[coq-defns ""])
|
||||||
(define body
|
(define output
|
||||||
(let ([body (output-coq #'body)])
|
(let ([body (output-coq #'body)])
|
||||||
(if (equal? body "")
|
(if (regexp-match "^\\s*$" body)
|
||||||
""
|
""
|
||||||
(format "Eval compute in ~a." body))))
|
(format "Eval compute in ~a." body))))
|
||||||
(displayln (format "~a~a" (coq-defns) body))
|
(displayln (format "~a~a" (coq-defns) output))
|
||||||
#'(begin))]))
|
#'(begin))]))
|
||||||
|
|
||||||
(module+ test
|
(module+ test
|
||||||
(require "stdlib/sugar.rkt")
|
|
||||||
(begin-for-syntax
|
(begin-for-syntax
|
||||||
(require rackunit)
|
|
||||||
(check-equal?
|
(check-equal?
|
||||||
(parameterize ([coq-defns ""]) (output-coq #'(data nat : Type (z : nat))) (coq-defns))
|
(parameterize ([coq-defns ""]) (output-coq #'(data nat : Type (z : nat))) (coq-defns))
|
||||||
(format "Inductive nat : Type :=~n| z : nat.~n"))
|
(format "Inductive nat : Type :=~n| z : nat.~n"))
|
||||||
|
@ -275,9 +370,9 @@
|
||||||
(output-coq #'(-> Type Type)))
|
(output-coq #'(-> Type Type)))
|
||||||
(let ([t (parameterize ([coq-defns ""])
|
(let ([t (parameterize ([coq-defns ""])
|
||||||
(output-coq #'(define-relation (meow gamma term type)
|
(output-coq #'(define-relation (meow gamma term type)
|
||||||
[(g : gamma) (e : term) (t : type)
|
[(g : gamma) (e : term) (t : type)
|
||||||
--------------- T-Bla
|
--------------- T-Bla
|
||||||
(meow g e t)]))
|
(meow g e t)]))
|
||||||
(coq-defns))])
|
(coq-defns))])
|
||||||
(check-regexp-match
|
(check-regexp-match
|
||||||
"Inductive meow : \\(forall temp. : gamma, \\(forall temp. : term, \\(forall temp. : type, Type\\)\\)\\) :="
|
"Inductive meow : \\(forall temp. : gamma, \\(forall temp. : term, \\(forall temp. : type, Type\\)\\)\\) :="
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
not
|
not
|
||||||
and
|
and
|
||||||
conj
|
conj
|
||||||
thm:any-is-symmetric proof:and-is-symmetric
|
thm:and-is-symmetric proof:and-is-symmetric
|
||||||
thm:proj1 proof:proj1
|
thm:proj1 proof:proj1
|
||||||
thm:proj2 proof:proj2
|
thm:proj2 proof:proj2
|
||||||
== refl)
|
== refl)
|
||||||
|
|
|
@ -82,3 +82,4 @@
|
||||||
;; because reasons. So manually insert a run in the type annotation
|
;; because reasons. So manually insert a run in the type annotation
|
||||||
(define-syntax-rule (qed thm pf)
|
(define-syntax-rule (qed thm pf)
|
||||||
((lambda (x : (run thm)) Type) pf))
|
((lambda (x : (run thm)) Type) pf))
|
||||||
|
|
||||||
|
|
14
stlc.rkt
14
stlc.rkt
|
@ -1,9 +1,11 @@
|
||||||
#lang s-exp "redex-curnel.rkt"
|
#lang s-exp "redex-curnel.rkt"
|
||||||
(require racket/trace "stdlib/nat.rkt" "stdlib/sugar.rkt" "oll.rkt"
|
(require racket/trace "stdlib/nat.rkt" "stdlib/sugar.rkt" "oll.rkt"
|
||||||
"stdlib/maybe.rkt")
|
"stdlib/maybe.rkt" "stdlib/bool.rkt" "stdlib/prop.rkt")
|
||||||
|
|
||||||
(define-language stlc
|
(define-language stlc
|
||||||
#:vars (x)
|
#:vars (x)
|
||||||
|
#:output-coq "stlc.v"
|
||||||
|
#:output-latex "stlc.tex"
|
||||||
(val (v) ::= true false unit)
|
(val (v) ::= true false unit)
|
||||||
;; TODO: Allow datum as terminals
|
;; TODO: Allow datum as terminals
|
||||||
(type (A B) ::= boolty unitty (-> A B) (* A A))
|
(type (A B) ::= boolty unitty (-> A B) (* A A))
|
||||||
|
@ -78,16 +80,18 @@
|
||||||
(emp-gamma : gamma)
|
(emp-gamma : gamma)
|
||||||
(ext-gamma : (->* gamma var stlc-type gamma)))
|
(ext-gamma : (->* gamma var stlc-type gamma)))
|
||||||
|
|
||||||
(define-rec (lookup-gamma (g : gamma) (x : var) : (maybe type))
|
(define-rec (lookup-gamma (g : gamma) (x : var) : (maybe stlc-type))
|
||||||
(case* g
|
(case* g
|
||||||
[emp-gamma (none type)]
|
[emp-gamma (none stlc-type)]
|
||||||
[(ext-gamma (g1 : gamma) (v1 : var) (t1 : type))
|
[(ext-gamma (g1 : gamma) (v1 : var) (t1 : stlc-type))
|
||||||
(if (var-equal? v1 x)
|
(if (var-equal? v1 x)
|
||||||
(some type t1)
|
(some stlc-type t1)
|
||||||
(lookup-gamma g1 x))]))
|
(lookup-gamma g1 x))]))
|
||||||
|
|
||||||
|
|
||||||
(define-relation (has-type gamma stlc-term stlc-type)
|
(define-relation (has-type gamma stlc-term stlc-type)
|
||||||
|
#:output-coq "stlc.v"
|
||||||
|
#:output-latex "stlc.tex"
|
||||||
[(g : gamma)
|
[(g : gamma)
|
||||||
------------------------ T-Unit
|
------------------------ T-Unit
|
||||||
(has-type g (stlc-val-->-stlc-term stlc-unit) stlc-unitty)]
|
(has-type g (stlc-val-->-stlc-term stlc-unit) stlc-unitty)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user