Confusing trying to construct language terms

41 views
Skip to first unread message

Mike Urbach

unread,
Dec 5, 2019, 5:41:46 PM12/5/19
to nanopass-framework
Hi,

I'm using the nanopass framework in Racket. I've been having some trouble and I thought I'd reach out to the group.

In my situation, I would like to construct a language term using with-output-language, but I am not able to do it the way I would expect. For simplicity, here is an example language:

#lang nanopass

(define-language example
  (terminals
   (symbol (s)))
  (Expr (e)
   (s0 ((s1 s2) ...))))

I can use this language to parse expressions as expected:

example.rkt> (define-parser p example)
example.rkt> (p '(test ((a b) (c d))))
(language:example '(test ((a b) (c d))))

However, in my compiler, I will need to generate that list ((a b) (c d)) programmatically. My approach was to construct the list, and use with-output-language to construct a language term using quasiquote. Something like this:

(with-output-language (example Expr)
  (let ([symbol-list '((a b) (c d))])
    `(test ,symbol-list)))

This results in an error:

; stdin::27080: test: invalid pattern or template                                                                                                                                                      
;   in: (test (unquote symbol-list))                                                                                                                                                                    

I know that something about using unquote to insert the list is wrong. If I manually type the list in, it will work as expected. For example:

(with-output-language (example Expr)
  `(test ((a b) (c d))))

What is the proper way to construct a language term in this case? I will need to build up a plain old Racket list elsewhere in my compiler, and insert it into a language term somehow. Perhaps using with-output-language like this is not the right approach, or perhaps there is a different way to unquote the variable that the list is bound to so that nanopass will not complain about the invalid pattern or template. I looked through the example compiler on GitHub, but it seemed like this approach should work.

Any help would be appreciated!

Thanks,

Mike

Andy Keep

unread,
Dec 5, 2019, 8:08:16 PM12/5/19
to Mike Urbach, nanopass-framework
Hey Mike,

When you are using with-output-language (or in the body of a pass), the nanopass framework does not attempt to parse s-expressions into the underlying Racket struct types, it looks for each field to be separately specified.  So, the form: (s0 ((s1 s2) …) is represented by a struct with three fields: s0, s1, and s2 where s0 is a symbol and s1 and s2 are both lists of symbols.  So you have to break the symbol-list down into the s1 list and the s2 list:

(with-output-language (example Expr)

  (let ([symbol-list '((a b) (c d))])

    `(test ((,(map car symbol-list) ,(map cadr symbol-list)) ...))))


Note that the … is also needed.


-andy:)

--
You received this message because you are subscribed to the Google Groups "nanopass-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nanopass-framew...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nanopass-framework/46b02987-6f4b-4d02-b930-5703c061d016%40googlegroups.com.

Jens Axel Søgaard

unread,
Dec 5, 2019, 8:13:19 PM12/5/19
to Andy Keep, Mike Urbach, nanopass-framework
Hi Mike,

Andy beat me to it, but here is a few examples:

#lang nanopass

(define-language example
  (terminals
   (symbol (s)))
  (Expr (e)
   (s0 ((s1 s2) ...))))

(with-output-language (example Expr)
  `(a ((b c))))

(with-output-language (example Expr)
  (define a 'A)
  (define b 'B)
  (define c 'C)
  `(,a ((,b ,c))))

(with-output-language (example Expr)
  (define a1 'A)
  (define bs '(b1 b2))
  (define cs '(c1 c2))
  `(,a1 ((,bs ,cs) ...)))


Andy:
In the last example I had to rename a to a1. Otherwise I get this error

; /Users/soegaard/tmp/mu.rkt:25:10: module: identifier already defined
;   at: a
;   in: (define-values (a) (quote A))
; [Due to errors, REPL is just module language, requires, and stub definitions]

If I wrap the body with a (let () ...) it works fine.

I was expecting with-output-language to implicitly wrap its body in a (let () ...).
Is it intentional or a bug?

/Jens Axel







--
--
Jens Axel Søgaard

Mike Urbach

unread,
Dec 5, 2019, 8:17:45 PM12/5/19
to nanopass-framework
Hi Andy,

Thanks for the quick reply and for setting me straight. I realize this is spelled out right in the documentation... not sure why I wasn't getting it earlier.

Anyway, thanks again for the tip and for all the hard work. The more I use this framework the more I like it!

Mike

Andy Keep

unread,
Dec 5, 2019, 10:16:16 PM12/5/19
to Jens Axel Søgaard, Mike Urbach, nanopass-framework
Hey Jens,

with-output-language is intentionally a splicing form (so it does not wrap the contents in a (let () …)).  I actually use this quite frequently in Scheme code where I do things like:

(with-output-language (L Expr)
  (define (foo x)
    —
     `(qux ,x))
  (define (bar x)
    —
    `(quux ,x)))
---
(foo (bar x))

-andy:)

Jens Axel Søgaard

unread,
Dec 6, 2019, 11:31:42 AM12/6/19
to Andy Keep, Mike Urbach, nanopass-framework
Den fre. 6. dec. 2019 kl. 04.16 skrev Andy Keep <andy...@gmail.com>:
Hey Jens,

with-output-language is intentionally a splicing form (so it does not wrap the contents in a (let () …)). 

Splicing! I think it's just one of the areas where convention in Scheme and Racket land has diverged.
I am so used to with- (as in with-syntax) being non-splicing that it didn't cross my mind.

/Jens Axel
Reply all
Reply to author
Forward
0 new messages