akeep / nanopass-framework

The new nanopass framework; an embedded DSL for writing compilers in Scheme

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failure with dot syntax parsing in passes

tufty opened this issue · comments

Consider the following language, which parses fine

(define-language Lx
  (terminals
   (symbol (x)))
  (Expr (e)
   x
   (lambda (x* ... . x) e)
   (define (x x* ... . x1) e)
   (define x e)))

a totally automated (effectively null) pass works:

(define-pass Px0 : Lx (ir) -> Lx ()
  (Expr : Expr (ir) -> Expr()))

And, using echo-define-pass, expands to

(define Px0
  (lambda (ir)
    (define who 'Px0)
    (define-nanopass-record)
    (define Expr
      (lambda (ir)
        (let ([#{g104 o3tk3lwitutvs130etsr6d-140} ir])
          (let-syntax ([quasiquote '#<procedure>]
                       [in-context '#<procedure>])
            (begin
              (let ()
                (cond
                  [(symbol? #{g104 o3tk3lwitutvs130etsr6d-140})
                   #{g104 o3tk3lwitutvs130etsr6d-140}]
                  [else
                   (let ([tag (nanopass-record-tag
                                #{g104 o3tk3lwitutvs130etsr6d-140})])
                     (cond
                       [(eqv? tag 1)
                        (make-Lx:lambda:Expr.1175 'Px0
                          (Lx:lambda:Expr.1175-x*
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Lx:lambda:Expr.1175-x
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Expr
                            (Lx:lambda:Expr.1175-e
                              #{g104 o3tk3lwitutvs130etsr6d-140}))
                          "x*" "x" "e")]
                       [(eqv? tag 2)
                        (make-Lx:define:Expr.1176 'Px0
                          (Lx:define:Expr.1176-x
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Lx:define:Expr.1176-x*
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Lx:define:Expr.1176-x1
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Expr
                            (Lx:define:Expr.1176-e
                              #{g104 o3tk3lwitutvs130etsr6d-140}))
                          "x" "x*" "x1" "e")]
                       [(eqv? tag 3)
                        (make-Lx:define:Expr.1177 'Px0
                          (Lx:define:Expr.1177-x
                            #{g104 o3tk3lwitutvs130etsr6d-140})
                          (Expr
                            (Lx:define:Expr.1177-e
                              #{g104 o3tk3lwitutvs130etsr6d-140}))
                          "x" "e")]
                       [else
                        (error 'Px0
                          "unexpected Expr"
                          #{g104 o3tk3lwitutvs130etsr6d-140})]))])))))))
    (let ([x (Expr ir)])
      (unless ((lambda (x) (or (Lx:Expr.1174? x) (symbol? x))) x)
        (error 'Px0 (format "expected ~s but got ~s" 'Expr x)))
      x)))

All well and good. However, if I wish to transform (define (x x* ... . x1) e) into (define x (lambda ....)) form, I need to manually specify the transformation. The following pass would appear to be correct:

(define-pass Px1 : Lx (ir) -> Lx ()
  (Expr : Expr (ir) -> Expr()
        [(define (,x ,x* ... . ,x1) ,[e])
         `(define ,x (lambda (,x* ... . ,x1) ,[e]))]))

However, I get the following error :

Exception in meta-parse-term: invalid pattern or template ((unquote x) (unquote x*) ... unquote x1)

The converse transformation, for example the following (contrived) pass, works fine

(define-pass Px2 : Lx (ir) -> Lx ()
  (Expr : Expr (ir) -> Expr ()
    [(define ,x ,[e])
     `(lambda (,x . test) ,e)]))

(unparse-Lx (Px2 (parse-Lx '(define foo bar))))
(lambda (foo . test) bar)

I can see why it's happening, but I can't see an easy way around it without adding syntax to the specification of match patterns.

Thanks for the bug report!

I think the dot syntax is not something that we have explicit support for... in fact I tried to get the following language to work and got a syntax error:

(define-language L
  (terminals
    (symbol (x)))
  (Expr (e)
    x
    (pair e0 . e1)))

and got a syntax error. (This is clearly something we are not checking for though, because we were getting a generic syntax error, which is part of the reason I think this is partially working for your example language).

That being said, I don't see any reason not to support this syntax, so I'll take a look at how this works and see if I can fix the meta-parser (which is the part that is breaking) to do the right thing here.

One thing to note, is that when you have a production like (define (x x* ... . x1) e) this will create a new record to store this with 4 fields: x (a single symbol), x* (a list of symbols), x1 (a single symbol), e (a single Expr record or symbol---based on your Expr nonterminal). So, there is no advantage to using the dot syntax in internal languages---other then that it may have some semantic meaning to you. Again, I see no reason not to support this though, and it can be quite handy if your source language has these features.

Again, thanks for the bug report, and I'll try to see if I can get this working :)

Okay. I think I've fixed this bug, and I've added your example to my tests, so the problem should not crop up again.

I did notice that your example pass had a small bug in it. In the the template you have:

`(define ,x (lambda (,x* ... ,x1) ,[e]))

after I fixed my bug it took me a minute to figure out what was going on, so I wanted to let you know and hopefully short cut that fix for you... here is the fixed pass.

(define-pass Px1 : Lx (ir) -> Lx ()
  (Expr : Expr (ir) -> Expr()
        [(define (,x ,x* ... . ,x1) ,[e])
         `(define ,x (lambda (,x* ... . ,x1) ,e))]))

Thanks again for the bug report, let me know if you run into other problems.

-andy:)

Andy, you're a star.