How to generator / emit code?

31 views
Skip to first unread message

Amirouche Boubekki

unread,
Jul 23, 2019, 7:02:12 AM7/23/19
to nanopass-framework
I am trying to generate JavaScript using a final pass, but I can not figure
the correct code.

Here is the code for my generate-javascript pass:

(define-pass generate-javascript : L6 (e) -> * ()
 
(definitions
   
(define string-join
     
(lambda (str* jstr)
       
(cond
         
[(null? str*) ""]
         
[(null? (cdr str*)) (car str*)]
         
[else (string-append (car str*) jstr (string-join (cdr str*) jstr))])))

   
;; symbol->c-id - converts any Scheme symbol into a valid C identifier.
   
(define symbol->c-id
     
(lambda (sym)
       
(let ([ls (string->list (symbol->string sym))])
         
(if (null? ls)
             
"_"
             
(let ([fst (car ls)])
               
(list->string
                 
(cons
                 
(if (char-alphabetic? fst) fst #\_)
                 
(map (lambda (c)
                         
(if (or (char-alphabetic? c)
                                 
(char-numeric? c))
                             c
                             
#\_))
                       
(cdr ls)))))))))

   
(define format-set!
     
(lambda (x rhs)
       
(format "~a = ~a" (symbol->c-id x) rhs))))

 
(Expr : Expr (e) -> * ()
       
[(if ,[e0] ,[e1] ,[e2])
         
(format "if (~a) {\n~a\n} else {\n~a}" e0 e1 e2)]

       
[(set! ,x ,[e])
         
(format-set! x e)]

       
[(lambda (,x* ...) ,[body])
         
(format "function(~a) {\n~a\n}"
                 
(string-join (map symbol->c-id x*) ", ")
                 body
)]

       
;; primitive application
       
[(,pr ,[e*] ...)
         
(format "~a(~a)"
                 pr
                 
(string-join e* ", "))]

       
;; lambda application
       
[(,[e] ,[e*] ...)
         
(format "~a(~a)"
                 e
                 
(string-join e* ", "))]
       
[pr pr]))

What ever I try I get errors. With the above code the error is:

Exception in nano-meta-fields: #[#{nano-quote cgcczz9hmtue79yz919bpk-310} (#<syntax quote> #<syntax pr [line 1064, char 10 of javascript.ss]>)] is not of type #<record type nano-meta>

Can someone help?

Thanks in advance!

Jens Axel Søgaard

unread,
Jul 23, 2019, 7:27:41 AM7/23/19
to Amirouche Boubekki, nanopass-framework
Den tir. 23. jul. 2019 kl. 13.02 skrev Amirouche Boubekki <amirouche...@gmail.com>:
I am trying to generate JavaScript using a final pass, but I can not figure
the correct code.

Is it the last line (which line is number 1064)?

    [pr pr]

Maybe   [,pr pr]

Apropos generating javascript: 
  I can recommend emitting a tree (made of cons-cells) of strings and numbers.
 Instead of using format one can simply use list:


   (format "~a = ~a" (symbol->c-id x) rhs)))
becomes
      (list (symbol->c-id x) "=" rhs)

The advantage is that no new strings are allocated during code generation.
An (string-append a b) becomes (list a b) and allocating a list is cheaper than string concatenation.

Emitting the contents of the tree is simple:

; emit : tree -> void
; display the elements in the tree in order
(define (emit x)
(cond
[(or (number? x)
(string? x)) (display x)]
[(symbol? x) (display x) (display " ")]
[(identifier? x) (display (mangle x))]
[(list? x) (for-each emit x)]
[else
(displayln x)
(error 'emit "got ~a" x)]))
--
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/3408d0da-d704-446f-a57e-5754af16a3b3%40googlegroups.com.


--
--
Jens Axel Søgaard

Amirouche Boubekki

unread,
Jul 24, 2019, 5:15:07 AM7/24/19
to nanopass-framework
Hello Jens,

Thanks for the reply.

On Tuesday, July 23, 2019 at 1:27:41 PM UTC+2, jensaxel wrote:
Den tir. 23. jul. 2019 kl. 13.02 skrev Amirouche Boubekki <amirouch...@gmail.com>:
I am trying to generate JavaScript using a final pass, but I can not figure
the correct code.

Is it the last line (which line is number 1064)?

    [pr pr]

Maybe   [,pr pr]

That doesn't work.
 

Apropos generating javascript: 
  I can recommend emitting a tree (made of cons-cells) of strings and numbers.
 Instead of using format one can simply use list:

   (format "~a = ~a" (symbol->c-id x) rhs)))
becomes
      (list (symbol->c-id x) "=" rhs)

The advantage is that no new strings are allocated during code generation.
An (string-append a b) becomes (list a b) and allocating a list is cheaper than string concatenation.

Emitting the contents of the tree is simple:

; emit : tree -> void

; display the elements in the tree in order

(define (emit x)

(cond

[(or (number? x)

(string? x)) (display x)]

[(symbol? x) (display x) (display " ")]

[(identifier? x) (display (mangle x))]

[(list? x) (for-each emit x)]

[else

(displayln x)

(error 'emit "got ~a" x)]))

That is what I end up doing. But since scheme-to-c does something else, I was under the impression that relying on a pass to generate the target code was the nanopass way.


Thanks!




PS: I got a proof-of-concept scheme-to-javascript compiler that eliminates the call stack via a trampolining https://github.com/scheme-live/scheme-to-javascript/commit/19087538b9ca76ba064133b1f08167b7e1b2e427

PS2: nanopass framework is very neat!

Matt Jadud

unread,
Jul 24, 2019, 6:26:59 AM7/24/19
to Amirouche Boubekki, nanopass-framework
That is what I end up doing. But since scheme-to-c does something else, I was under the impression that relying on a pass to generate the target code was the nanopass way.

Having a single pass to do your output makes sense in the nanopass framework. I would keep everything in structures of some sort (structs, lists, whatever) until the very last moment, and then do the transformation to your output target.

There's a school of thought that your output should always be neat and human readable. On this point, your mileage may vary. If an external tool ("javascript-tidy", or whatever tool I am assuming exists that might tidy javascript)  can do the work for you, then it can be a simple pass that uses (system* ...) to do that work for you.
 
PS: I got a proof-of-concept scheme-to-javascript compiler that eliminates the call stack via a trampolining https://github.com/scheme-live/scheme-to-javascript/commit/19087538b9ca76ba064133b1f08167b7e1b2e427

Very cool. 

Cheers,
Reply all
Reply to author
Forward
0 new messages