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.
298 lines
12 KiB
Scheme
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)))])))
|
|
)
|