You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

298 lines
12 KiB
Scheme

(library (nanopass exp-syntax)
(export
define-language-exp
inspect-language lookup-language
Llanguage unparse-Llanguage
Lannotated unparse-Lannotated
language->s-expression-exp
prune-language-exp
define-pruned-language-exp
diff-languages-exp
define-language-node-counter-exp
define-unparser-exp
define-parser-exp
)
(import (rnrs) (nanopass) (nanopass experimental) (nanopass helpers)
(only (chezscheme) make-compile-time-value trace-define-syntax unbox
optimize-level enumerate with-output-to-string errorf))
(define-syntax define-language-exp
(lambda (x)
(lambda (rho)
(syntax-case x ()
[(_ . rest)
(let* ([lang (parse-np-source x 'define-language-exp)]
[lang (handle-language-extension lang 'define-language-exp rho)]
[lang (check-and-finish-language lang)]
[lang-annotated (annotate-language lang)])
(nanopass-case (Llanguage Defn) lang
[(define-language ,id ,cl* ...)
#`(begin
(define-language . rest)
(define-property #,id experimental-language
(make-language-information '#,lang '#,lang-annotated))
(define-language-records #,id)
#;(define-language-predicates #,id))]))]))))
(define-syntax inspect-language
(lambda (x)
(lambda (rho)
(syntax-case x ()
[(_ name)
(let ([lang (rho #'name)])
(if lang
(let ([l (language-information-language lang)]
[a (language-information-annotated-language lang)])
#`(list
'#,l
'#,(datum->syntax #'* (unparse-Llanguage l))
'#,a
'#,(datum->syntax #'* (unparse-Lannotated a))))
(syntax-violation 'inspect-language "no language found" #'name)))]))))
(define (build-list-of-string level name)
(with-output-to-string
(lambda ()
(let loop! ([level level])
(if (fx=? level 0)
(write name)
(begin (display "list of ") (loop! (fx- level 1))))))))
(define-syntax define-language-records
(lambda (x)
(define-pass construct-records : Lannotated (ir) -> * (stx)
(definitions
(define (build-field-check name mv level pred)
#`(lambda (x msg)
(define (squawk level x)
(if msg
(errorf who "expected ~a but received ~s in field ~s from ~a"
(build-list-of-string level '#,name) x '#,mv msg)
(errorf who "expected ~a but received ~s in field ~s"
(build-list-of-string level '#,name) x '#,mv)))
#,(let f ([level level])
(if (fx=? level 0)
#`(lambda (x) (unless (#,pred x) (squawk #,level x)))
#`(lambda (x)
(let loop ([x x])
(cond
[(pair? x) (#,(f (fx- level 1)) (car x))]
[(null? x)]
[else (squawk #,level x)]))))))))
(Defn : Defn (ir) -> * (stx)
[(define-language ,id ,ref ,id0? ,rtd ,rcd ,tag-mask (,term* ...) ,[nt*] ...)
#`(begin #,@nt*)])
(Nonterminal : Nonterminal (ir) -> * (stx)
[(,id (,id* ...) ,b ,rtd ,rcd ,tag ,pred ,all-pred ,all-term-pred ,prod* ...)
(let ([stx* (map (lambda (prod) (Production prod rcd)) prod*)])
#`(begin (define #,pred (record-predicate '#,rtd)) #,@stx*))])
(Production : Production (ir nt-rcd) -> * (stx)
[(production ,pattern ,pretty-prod? ,rtd ,tag ,pred ,maker ,[mv* acc* check*] ...)
(with-syntax ([(mv* ...) mv*]
[(msg* ...) (generate-temporaries mv*)]
[(check* ...) check*]
[(acc* ...) acc*]
[(idx ...) (enumerate acc*)])
#`(begin
(define #,maker
(let ()
(define maker
(record-constructor
(make-record-constructor-descriptor '#,rtd '#,nt-rcd
(lambda (pargs->new)
(lambda (mv* ...)
((pargs->new #,tag) mv* ...))))))
(lambda (who mv* ... msg* ...)
#,@(if (fx=? (optimize-level) 3)
'()
#`((check* mv* msg*) ...))
(maker mv* ...))))
(define #,pred (record-predicate '#,rtd))
(define acc* (record-accessor '#,rtd idx)) ...))]
[else #'(begin)])
(Field : Field (ir) -> * (mv check acc)
[(,[mv name pred] ,level ,accessor)
(values mv accessor (build-field-check name mv level pred))]
[(optional ,[mv name pred] ,level ,accessor)
(values mv accessor
(build-field-check name mv level
#`(lambda (x) (or (eq? x #f) (#,pred x)))))])
(Reference : Reference (ir) -> * (mv name pred)
[(term-ref ,id0 ,id1 ,b)
(values id0 id1 (TerminalPred (unbox b)))]
[(nt-ref ,id0 ,id1 ,b)
(values id0 id1 (NonterminalPred (unbox b)))])
(TerminalPred : Terminal (ir) -> * (name pred)
[(,id (,id* ...) ,b ,handler? ,pred) pred])
(NonterminalPred : Nonterminal (ir) -> * (name pred)
[(,id (,id* ...) ,b ,rtd ,rcd ,tag ,pred ,all-pred ,all-term-pred ,prod* ...)
all-pred])
(Defn ir))
(syntax-case x ()
[(_ name)
(lambda (rho)
(let ([lang (lookup-language rho #'name)])
(construct-records (language-information-annotated-language lang))))])))
(define-syntax define-language-predicates
(lambda (x)
(define-pass language-predicates : Lannotated (ir) -> * (stx)
(definitions
(define (set-cons x ls)
(if (memq x ls)
ls
(cons x ls))))
(Defn : Defn (ir) -> * (stx)
[(define-language ,id ,ref ,id0? ,rtd ,rcd ,tag-mask (,term* ...) ,nt* ...)
(let loop ([nt* nt*] [ntpreddef* '()] [tpred* '()])
(if (null? nt*)
(with-syntax ([pred (construct-id id id "?")]
[(tpred* ...) tpred*])
#`(begin
(define pred
(lambda (x)
(or ((record-predicate '#,rtd) x) (tpred* x) ...)))
#,@ntpreddef*))
(let-values ([(ntpreddef* tpred*) (Nonterminal (car nt*) ntpreddef* tpred*)])
(loop (cdr nt*) ntpreddef* tpred*))))])
(Nonterminal : Nonterminal (nt ntpreddef* lang-tpred*) -> * (ntpreddef* lang-tpred*)
[(,id (,id* ...) ,b ,rtd ,rcd ,tag ,pred ,all-pred ,all-term-pred ,prod* ...)
(let loop ([prod* prod*] [pred* '()] [lang-tpred* lang-tpred*])
(if (null? prod*)
(values
(cons
(with-syntax ([(pred* ...) pred*])
#`(define #,all-pred
(lambda (x)
(or ((record-predicate '#,rtd) x) (pred* x) ...))))
ntpreddef*)
lang-tpred*)
(let-values ([(tpred* lang-tpred*) (Production (car prod*) pred* lang-tpred*)])
(loop (cdr prod*) tpred* lang-tpred*))))])
(Production : Production (ir pred* lang-tpred*) -> * (pred* lang-tpred*)
[(terminal (term-ref ,id0 ,id1 ,b) ,pretty-prod?)
(let ([pred (TerminalPred (unbox b))])
(values (cons pred pred*) (set-cons pred lang-tpred*)))]
[(nonterminal (nt-ref ,id0 ,id1 ,b) ,pretty-prod?)
(values (cons (NonterminalPred (unbox b)) pred*) lang-tpred*)]
[else (values pred* lang-tpred*)])
(TerminalPred : Terminal (ir) -> * (pred)
[(,id (,id* ...) ,b ,handler? ,pred) pred])
(NonterminalPred : Nonterminal (ir) -> * (pred)
[(,id (,id* ...) ,b ,rtd ,rcd ,tag ,pred ,all-pred ,all-term-pred ,prod* ...) all-pred])
(Defn ir))
(syntax-case x ()
[(_ name)
(lambda (rho)
(let ([lang (lookup-language rho #'name)])
(language-predicates (language-information-annotated-language lang))))])))
(define-syntax language->s-expression-exp
(lambda (x)
(define-pass lang->sexp : Llanguage (ir) -> * (sexp)
(Defn : Defn (ir) -> * (sexp)
[(define-language ,id ,[cl*] ...)
`(define-language ,(syntax->datum id) . ,cl*)])
(Clause : Clause (ir) -> * (sexp)
[(entry ,[sym]) `(entry ,sym)]
[(nongenerative-id ,id)
`(nongenerative-id ,(syntax->datum id))]
[(terminals ,[term*] ...)
`(terminals . ,term*)]
[(,id (,id* ...) ,b ,[prod*] ...)
`(,(syntax->datum id) ,(map syntax->datum id*) . ,prod*)])
(Terminal : Terminal (ir) -> * (sexp)
[,simple-term (SimpleTerminal simple-term)]
[(=> ,[simple-term] ,handler)
`(=> ,simple-term ,(syntax->datum handler))])
(SimpleTerminal : SimpleTerminal (ir) -> * (sexp)
[(,id (,id* ...) ,b)
`(,(syntax->datum id) ,(map syntax->datum id*))])
(Production : Production (ir) -> * (sexp)
[,pattern (Pattern pattern)]
[(=> ,[pattern0] ,[pattern1])
`(=> ,pattern0 ,pattern1)]
[(-> ,[pattern] ,handler)
`(-> ,pattern ,(syntax->datum handler))])
(Pattern : Pattern (ir) -> * (sexp)
[(maybe ,[sym]) `(maybe ,sym)]
[,ref (Reference ref)]
[,id (syntax->datum id)]
[(,[pattern0] ,dots . ,[pattern1])
`(,pattern0 ... . ,pattern1)]
[(,[pattern0] . ,[pattern1])
`(,pattern0 . ,pattern1)]
[,null '()])
(Reference : Reference (ir) -> * (sym)
[(term-ref ,id0 ,id1 ,b) (syntax->datum id0)]
[(nt-ref ,id0 ,id1 ,b) (syntax->datum id0)])
(Defn ir))
(syntax-case x ()
[(_ name)
(lambda (rho)
(let ([lang (lookup-language rho #'name)])
#`'#,(datum->syntax #'*
(lang->sexp
(language-information-language lang)))))])))
(define-syntax prune-language-exp
(lambda (x)
(syntax-case x ()
[(_ name)
(lambda (rho)
(let ([lang (lookup-language rho #'name)])
(with-syntax ([pl (prune-lang
(language-information-annotated-language lang)
'prune-language-exp
#f)])
#'(quote pl))))])))
(define-syntax define-pruned-language-exp
(lambda (x)
(syntax-case x ()
[(_ name new-name)
(lambda (rho)
(let ([lang (lookup-language rho #'name)])
(prune-lang
(language-information-annotated-language lang)
'define-pruned-language-exp
#'new-name)))])))
(define-syntax diff-languages-exp
(lambda (x)
(syntax-case x ()
[(_ name0 name1)
(lambda (rho)
(let ([lang0 (lookup-language rho #'name0)]
[lang1 (lookup-language rho #'name1)])
(with-syntax ([diff (diff-langs
(language-information-language lang0)
(language-information-language lang1))])
#'(quote diff))))])))
(define-syntax define-language-node-counter-exp
(lambda (x)
(syntax-case x ()
[(_ name lang)
(lambda (rho)
(let ([l (lookup-language rho #'lang)])
(build-lang-node-counter (language-information-annotated-language l) #'name)))])))
(define-syntax define-unparser-exp
(lambda (x)
(syntax-case x ()
[(_ name lang)
(lambda (rho)
(let ([l (lookup-language rho #'lang)])
(build-unparser (language-information-annotated-language l) #'name)))])))
(define-syntax define-parser-exp
(lambda (x)
(syntax-case x ()
[(_ name lang)
(lambda (rho)
(let ([l (lookup-language rho #'lang)])
(build-parser (language-information-annotated-language l) #'name)))])))
)