akeep / nanopass-framework-racket Goto Github PK
View Code? Open in Web Editor NEWRacket port of the nanopass-framework
License: MIT License
Racket port of the nanopass-framework
License: MIT License
I think we can use default values for extra formal parameters in the define-pass form:
(define-pass name : lang-specifier (formal ...) -> lang-specifier (extra-return-val ...)
definitions-clause
processor ...
body-expr)
And the following code works:
(define-language L
(entry Expr)
(terminals
(number (n)))
(Expr (e)
n
(someop e)))
(define-parser parse-L L)
(define-pass as-bin : L (ir global-ctx) -> L ()
( as-binary : Expr (ir [ctx global-ctx]) -> Expr ()
[,n (modulo n 2)]
[(someop ,[e? 'val-b -> e]) `(someop ,e)]))
; usage:
; (as-bin (parse-L '(someop 4)) 'val-default)
; or
; ((compose (curryr as-bin 'val-default) parse-L) '(someop 4))
But only the processor as-binary
can have the default value, and I think It would be cool to be able to also write default values as the define
statement does:
; ⬐---------here---------⬎
(define-pass as-bin : L (ir [global-ctx 'val-default]) -> L ()
( as-binary : Expr (ir [ctx global-ctx]) -> Expr ()
[,n (modulo n 2)]
[(someop ,[e? 'val-b -> e]) `(someop ,e)]))
; suggested usage:
; (as-bin (parse-L '(someop 4)))
; or
; ((compose as-bin parse-L) '(someop 4))
The documentation does not say anything about default parameters:
formal is an identifier representing a formal argument.
The following program gives the error:
../../Applications/Racket v6.2/collects/racket/contract/private/blame.rkt:143:0: make-language: contract violation
expected: identifier?
given: #f
in: the 2nd argument of
(->
identifier?
identifier?
(listof tspec?)
(listof ntspec?)
language?)
contract from:
/nanopass-framework-racket/private/records.rkt
blaming: /nanopass-framework-racket/private/language.rkt
(assuming the contract is correct)
at: /nanopass-framework-racket/private/records.rkt:65.5
#lang nanopass
(define variable? symbol?)
(define-language L
(entry Expr)
(terminals
(variable (x)))
(Expr (e)
x))
(define-language L1
(terminals
(+ (variable l))))
(define-language Lsrc
(entry Expr)
(terminals
(symbol (x))
(syntax (s)))
(Binding (b)
[(x ...) e])
(Expr (e)
x
(let-values s (b ...) e0 e1 ...)))
Dropbox/GitHub/nanopass-framework-racket/private/records.rkt:465:43: unique-symbol: contract violation
expected: identifier?
given: #<syntax:9:5 (x ...)>
in: an element of
the rest argument of
(->*
(identifier?)
#:rest
(listof identifier?)
symbol?)
contract from:
/nanopass-framework-racket/private/helpers.rkt
blaming: /nanopass-framework-racket/private/records.rkt
(assuming the contract is correct)
at: /nanopass-framework-racket/private/helpers.rkt:34.5
In the program below Foo is not bound as a nonterminal.
The program provokes an internal error rather than "Error: Foo is not defined as a nonterminal".
(define-language Lsrc
(entry Expr)
(terminals
(symbol (x)))
(Expr (e)
x))
(define-pass parse : * (stx) -> Lsrc ()
(definitions)
(foo : * (E) -> Foo ()
`,'t)
(foo stx))
The following program gives the error:
nanopass-framework-racket/private/meta-parser.rkt:243:27: tspec-type: broke its contract
promised: identifier?
produced: 'symbol
in: the range of
(-> tspec? identifier?)
contract from:
<pkgs>/nanopass-framework-racket/private/records.rkt
blaming: <pkgs>/nanopass-framework-racket/private/records.rkt
(assuming the contract is correct)
at: <pkgs>/nanopass-framework-racket/private/records.rkt:76.5
/Jens Axek
#lang nanopass
(define-language L
(entry Expr)
(terminals
(symbol (x)))
(Expr (e)
x
(x ...)))
(define-language L1 (extends L)
(Expr (e)
(+ (call e0 ...) => (e0 ...))))
(define (parse s)
(with-output-language (L Expr)
(cond
[(symbol? s) `,s]
[(list? s) `(,s ...)]
[else (error)])))
(define-pass pass1 : L (E) -> L1 ()
(definitions)
(Expr : Expr (E) -> Expr ()
[(,[x] ...) `(call ,x ...)]))
(unparse-L1
(pass1
(parse '(x y z))))
After syntax checking DrRacket supports some nice features:
Consider this program:
#lang nanopass
(define-language L
(entry Expr)
(terminals (number (r)))
(Expr (e) r))
(with-output-language (L Expr) 1)
I would like to rename L but the renaming option is not available.
In order to support renaming one has to add properties:
Note that if the property 'sub-range-binders is used then a renaming of L to M
will also rename unparse-L to the unparse-M.
Same problem as the previous issue. Here L is unknown, but an internal error is given.
(define-pass pass1 : * (s-exp) -> L ()
42)
The following
(Expr : Expr (e dest) -> Expr ()
[(let-values ,s (((,x ...) ,ce) ...) ,e)
; todo handle multiple values
(let* ([x0 (map first x)] [ce (map CExpr ce x0)] [e (Expr e)])
`(let ([,x0 "undefined"] ...)
(body ,ce ... ,e)))])
produces the error
../../nanopass-framework-racket/private/meta-parser.rkt:415:39: cadr: contract violation
expected: (cons/c any/c pair?)
given: #<syntax (quote "undefined")>
The error ought should be an external error - not an internal one.
The following error does not highlight the offending form in DrRacket.
define-language: unrecognized production in subtract in: (define (f φ ...) b)
The following program provokes an internal error, rather than signaling one the user program.
(define-language L
(terminals (symbol (x)))
(term (t) x))
(define x 42)
(define-pass pass1 : L (t) -> * ()
(term : term (t) -> * ()
[x "it is a symbol"]))
The error is:
Dropbox/GitHub/nanopass-framework-racket/private/pass.rkt:319:33: nano-meta-fields: contract violation
expected: nano-meta?
given: '#s(nano-quote #<syntax (quote x)>)
in: the 1st argument of
(->
nano-meta?
(listof
(or/c
nano-dots?
nano-quote?
nano-unquote?
nano-cata?
nano-meta?
(listof any/c))))
contract from:
/nanopass-framework-racket/private/records.rkt
blaming: /nanopass-framework-racket/private/pass.rkt
(assuming the contract is correct)
at: /nanopass-framework-racket/private/records.rkt:44.5
When nanopass-case
is called with a value V that no clauses match and there is no default else-clause the error message doesn't show the value V. The entire form is printed. Note that the DrRacket seems to color more than the nanopass-case
expression red - which suggest that the source location is not correct.
Example of error message:
nanopass-case: empty else clause hit (nanopass-case (LFE2 GeneralTopLevelForm) T
((unquote e) (Expr e id)) ((define-values (unquote s) ((unquote x) ...) (unquote e))
(quasiquote (define-values (unquote s) ((unquote x) ...) (unquote (RHS e id)))))
((define-syntaxes (unquote s) ((unquote x) ...) (unquote e)) (quasiquote (define-syntaxes
(unquote s) ((unquote x) ...) (unquote (RHS e id))))))
<pkgs>/nodejs/nodejs/compiler.rkt:804.6
The program below gives the following internal error:
nanopass-framework-racket/private/records.rkt:467:52: car: contract violation
expected: pair?
given: 1
#lang nanopass
(define-language L
(terminals
(symbol (x)))
(entry Expr)
(Expr (e)
(1 2)
(e0 e1)))
(originally submitted over email to the nanopass-framework mailing list by Axel Søgaard)
The following programs compiles without errors:
(define variable? symbol?)
(define-language LFE
(entry TopLevelForm)
(terminals
(variable (x xd)))
(Formals (f) x)
(TopLevelForm (t) g)
(GeneralTopLevelForm (g) e)
(Expr (e) x))
(define-language LFE2 (extends LFE)
(Abstraction (ab)
(+ (λ f e) => (λ f e)))
(Expr (e)
(+ ab)))
(define-language LANF (extends LFE2)
(AExpr (ae)
(+ x
ab))
(CExpr (ce)
(+ ae))
(Expr (e)
(+ ae
ce)))
However, if I add the following expression, I get an error:
(λ()
(nanopass-case (LANF Expr) 43
[else 4]))
The (internal) compile time error I get is:
Dropbox/GitHub/nanopass-framework-racket/private/pass.rkt:1059:52: memf: not a proper list: '#s((nonterminal-alt #(0) alt 3) #<syntax:27:7 ae> #f #f #<syntax:21:3 AExpr>)
I know that 43 isn't an LANF Expression, but that's besides the point.
Note that if I change
(Expr (e)
(+ ae
ce)))
to
(Expr (e)
(+
ce)))
the error disappears.
Is the language definition correct?
This program provokes an internal error:
(define-pass categorize-applications : L0 (Expr) -> L1 ()
(definitions)
(Expr : Expr (E) -> Expr ()))
Dropbox/GitHub/nanopass-framework-racket/private/pass.rkt:1440:33: syntax-local-value: not defined as syntax identifier: #<syntax:3:39 L0>
A better error would be:
L0 is not defined as a nanopass language (using define-language)
I ran into this error:
../../nanopass-framework-racket/private/pass.rkt:1188:42: tspec-pred: contract violation
expected: tspec?
given: #f
in: the 1st argument of
(-> tspec? (or/c #f identifier?))
contract from:
/nanopass-framework-racket/private/records.rkt
blaming: /nanopass-framework-racket/private/pass.rkt
(assuming the contract is correct)
at: /nanopass-framework-racket/private/records.rkt:79.5
Hi ,
Please add the racket topic to this repo - I think others will be interested and this will help them find it at https://github.com/topics/racket
https://help.github.com/en/articles/classifying-your-repository-with-topics
Kind regards,
Stephen
The following program gives an internal error.
A better error message would be:
"Lsrc is not defined as a language"
Also the source location for the error should be Lsrc.
(define-language L1 (extends Lsrc)
(Expr (e) (- (if e0 e1))))
The current error:
nanopass-framework-racket/private/language.rkt:242:31: syntax-local-value: not defined as syntax
identifier: #<syntax:3:29 Lsrc>
This program gives the error "define-language: unrecognized clause in: (Expr r)".
Better wording:
"define-language: Expected nonterminal clause of the form
(keyword (meta-var ...) production-clause ...) in: (Expr r).
(define-language L
(entry Expr)
(terminals (number (r)))
(Expr r))
The following error typically occurs when an attempt to construct a nonterminal fails due
to the wrong type of a field value:
box-mutables: expected Expr but received
(let-values #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:517:16 ac>
(((((#(struct:variable #<syntax x.1>))) ...) ((app
#<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:517:16 ac>
#(struct:variable #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:520:33 box>)
(quote #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:517:16 ac>
#(struct:datum #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:517:16 ac>
-42))))) ...) #(struct:LFE1:app:Expr.43 91
#<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:517:16 ac>
#(struct:variable #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:519:33
set-box!>) (#(struct:variable #<syntax x.1>) #(struct:LFE1:quote:Expr.40 67
#<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:587:34 (quote 2)>
#(struct:datum #<syntax:/Users/soegaard/Dropbox/GitHub/nodejs/nodejs/compiler.rkt:587:34
(quote 2)> 2))))) in field e of (λ s f e) from expression (LambdaBody s f (formal-variables f) e)
<pkgs>/nodejs/nodejs/compiler.rkt:563.35
Notice that the important bit is at the very end:
in field e of (λ s f e) from expression (LambdaBody s f (formal-variables f) e)
< pkgs>/nodejs/nodejs/compiler.rkt:563.35
The location of the error is correct here: line 563.
The expression colored red in DrRacket is the last expression of the define-pass form
in which the (λ ,s ,f ,e) template appears however. [This is the issue reported].
Also note that the error begins with:
box-mutables: expected Expr but received
which tricks one to believe the problem lies somewhere where box-mutables is called with the wront type of argument. Maybe it were a good idea to move the last bit to the top?
This may or may not be a bug in nanopass-case
.
If there were a nanopass-mailing list I would tried there before filing an issue.
This works:
(let ([M (parse '((λ (x) x) 4))])
(nanopass-case (LCS Term) M
[(call ,M ,M1 ...) (list 'call M M1)]
[else 'huh]))
But this
(let ([M (parse '(let (y 5) 6))])
(nanopass-case (LCS Term) M
[(let (,x ,M) ,M1 ...) (list M M1)]
[else 'huh]))
gives the error:
define-pass: quoted terminals currently unsupported in match patterns in: (quote let)
The problem is that let
is defined as a non-terminal of Term in the language LCS.
I.e. it is not a quoted terminal.
Am I using nanopass-case
in the wrong way, or is there a bug?
The entire program is here:
This may not be solvable (or may require backtracking when constructing language). But I'll put this here anyway, and if it's not doable, we should output a better error message.
Let's say I have the following language;
#lang nanopass
(define-language Lsrc
(terminals
(symbol (s))
(number (n)))
(stmt (stmt)
n
expr
(begin stmt ...))
(expr (expr)
s
(begin expr ...)))
I cannot construct the following grammar:
(with-output-language (Lsrc stmt)
`(begin a 5))
Because it tries to use the expr begin
, rather then stmt's. (Which is understandable because an expr is a valid stmt.
So, this makes me think either we need to improve the pattern matcher to allow this, and at least try to pick the right one (if it exists anyway), or if I give an ambiguous grammar, give that as an error message.
The following program gives an error not in the user program but in the framework.
(define (constant? c)
(number? c))
(define-language L
(terminals
(constant (c)))
(Expr (e)
c))
(define (parse v)
(with-output-language (L Expr)
(cond
[(number? v) `,v]
[else (error 'parse "got: ~a" v)])))
(define-pass add1 : L (e) -> L ()
(Expr : Expr (e) -> Expr ()
[c (guard (even? c)) (+ c 1)]))
(add1 (parse 42))
The mistake made above is that [c (guard (even? c)) (+ c 1)] should have been [,c (guard (even? c)) (+ c 1)].
The error message given is shown below. It indicates an internal error.
Dropbox/GitHub/nanopass-framework-racket/private/pass.rkt:319:33: nano-meta-fields: contract violation
expected: nano-meta?
given: '#s(nano-quote #<syntax (quote c)>)
in: the 1st argument of
(->
nano-meta?
(listof
(or/c
nano-dots?
nano-quote?
nano-unquote?
nano-cata?
nano-meta?
(listof any/c))))
contract from:
/nanopass-framework-racket/private/records.rkt
blaming: /nanopass-framework-racket/private/pass.rkt
(assuming the contract is correct)
at: /nanopass-framework-racket/private/records.rkt:44.5
Here are two examples of problematic errors from with-output-language:
#lang nanopass
(define-language L
(entry Expr)
(terminals
(symbol (s)))
(Expr (e) s))
(with-output-language (L Foo)
`,3)
This first example gives there error
Dropbox/GitHub/nanopass-framework-racket/private/meta-parser.rkt:361:4: L: unrecognized nonterminal passed to meta parser Foo
But the error location is missing (Foo is not colored red).
The next example shows a missing error:
#lang nanopass
(define-language L
(entry Expr)
(terminals
(symbol (s)))
(Expr (e) s))
(with-output-language (L Foo)
3)
Compiles without errors. I expected to get the error: "Foo is not a nonterminal in L"
The following program provokes an "duplicate alt" error.
I suggest that the error location becomes (+ s)
.
The current error.
define-language: duplicate alt in add in: #s((terminal-alt #(0) alt 3) #<syntax:12:7 s> #f #f #f)
Could this message be improved?
#lang nanopass
(define-language L
(entry e)
(terminals
(symbol (s)))
(Expr (e)
s))
(define-language L1 (extends L)
(Expr (e)
(+ s)))
It seems that the Chez Scheme error procedure use a different convention than Racket.
Racket expects the following: (error src format-string v ...)
If there are no ~a (or similar) in the format string then an error will throw an error if there are any additional arguments present.
Below is a list of places where I think there could be problems.
The list is an edited version of the output of
grep -A3 "(error" *.rkt > errors.txt
run in nanopass-framework-racket/private/
parser.rkt: (error (if trace? 'trace-define-syntax 'define-syntax)
pass.rkt: [(terminal-alt? in-altrec) (error who "unexpected terminal alt" in-altrec)]
pass.rkt: #`(error '#,(pass-desc-name pass-desc)
pass.rkt- #,(format "unexpected ~s" (maybe-syntax->datum itype))
pass.rkt: #`(error '#,(pass-desc-name pass-desc)
pass.rkt- #,(format "unexpected ~s" (maybe-syntax->datum itype))
unparser.rkt: [else (error '#,name
unparser.rkt- "unrecognized language record"
unparser.rkt- ir)])])))))))
The following program uses the same variable twice.
The error is correct, but I expected DrRacket to highlight the second e in the definitions window.
(define (constant? c)
(number? c))
(define-language L
(terminals
(constant (c)))
(Expr (e)
c
(if e e)))
The error message should probably be:
"unrecognized language record in ~a"
https://github.com/akeep/nanopass-framework-racket/blob/master/private/unparser.rkt#L145
The following program gives this error:
error: format string requires 0 arguments, given 1; arguments were: 'unparse-L2 "unrecognized language record" (L1:foo:Term.2 2 'a)
(define-language L1
(terminals (symbol (x)))
(Term (M)
(foo x)))
(define-language L2
(terminals (symbol (x)))
(Term (M)
(foo x)))
(unparse-L2 (with-output-language (L1 Term) `(foo a)))
The following program simply reports bad syntax, but the error location is lost.
(define-language L1
(terminals (symbol x))
(Term (M)
x))
(define-language Lsrc
(entry Expr)
(terminals)
(Expr (e)
1))
In the following program I expect DrRacket to color the t red.
(define-language L
(entry e)
(terminals (symbol (s)))
(Expr (e)
(s ...) => (t ...)))
Also note that the error is worded in terms of extended-quasiquote and not define-language.
This program:
https://gist.github.com/soegaard/c921dd922b198b06729e
gives the internal error:
../nanopass-framework-racket/private/pass.rkt:302:6: car: contract violation
expected: pair?
given: #<syntax (((catch-finally (unquote x) ...>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.