[Chicken-users] struggling with macros
Hi, I'm trying to write a simple javascript DSL, and got stuck in the macros :). (I'm coming from lisp macros) Take for example this one: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( ))] ) It is supposed to handle numbers and function calls, without building the parameter list in the function calls. CSI (js 1) next=1 1 CSI (js (1 2 3)) next=(1 2 3) next=1 1() However, when trying to build the parameter list I get and error which I don't understand: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( (apply string-append (map js ,(cdr next))) ))] ) CSI (js (1 2 3)) next=(1 2 3) next=1 Error: unbound variable: js [ inspect ] Restarts: 0: [ABORT] Return to SLIME's top level Backtrace: 0: eval [ more... ] (map248 js245 (2 3)) 1: eval [ more... ] (apply247 string-append246 (map248 js245 (2 3))) 2: eval [ more... ] (string-append246 (js245 1) ( (apply247 string-append246 (map248 js245 (2 3))) )) 3: syntax (2 3) 4: syntax (map248 js245 (2 3)) 5: syntax (apply247 string-append246 (map248 js245 (2 3))) 6: eval [ more... ] (number-string next) 7: eval [ more... ] (number? next) 8: eval [ more... ] (printf next=~a~n next) 9: eval [ more... ] (cadr expr) 10: eval [ more... ] (cdr expr) 11: syntax (js245 1) 12: syntax (string-append246 (js245 1) ( (apply247 string-append246 (map248 js245 (2 3))) )) 13: eval [ more... ] (cdr next) 14: eval [ more... ] (##sys#list (##core#quote map) (##core#quote js) (cdr next)) 15: eval [ more... ] (##sys#list (##core#quote apply) (##core#quote string-append) (##sys#list (##core#quote map) (##core#quote js) (cdr next))) So, my questions are: 1/ Why is js not bound in the second example? I also tried to use letrec-syntax but with same result. 2/ Are there other ways to achieve what I want? 3/ I also tried to use syntax-rules, but from what I understood this is not possible, because you can't execute arbitrary expressions (in this case a cond) at macroexpansion time. Am I right here? Thanks, Răzvan ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users
Re: [Chicken-users] struggling with macros
On Sun, Nov 11, 2012 at 01:23:13PM +0100, Răzvan Rotaru wrote: Hi, Hi! I'm trying to write a simple javascript DSL, and got stuck in the macros :). (I'm coming from lisp macros) Take for example this one: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( ))] ) It is supposed to handle numbers and function calls, without building the parameter list in the function calls. It's doing this correctly, is it? However, when trying to build the parameter list I get and error which I don't understand: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( (apply string-append (map js ,(cdr next))) ))] ) CSI (js (1 2 3)) next=(1 2 3) next=1 Error: unbound variable: js You're trying to use MAP on a macro. That's not possible because macros are not first-class (this is true in Common Lisp as well). 1/ Why is js not bound in the second example? I also tried to use letrec-syntax but with same result. Because of map. 2/ Are there other ways to achieve what I want? I don't understand what you're trying to do here. 3/ I also tried to use syntax-rules, but from what I understood this is not possible, because you can't execute arbitrary expressions (in this case a cond) at macroexpansion time. Am I right here? Indeed. You can expand to a cond, but that would be less efficient. On the other hand, this macro will only work on string literals. Perhaps the user would like to be able to use variables containing strings, which would be impossible in this case. Cheers, Peter -- http://sjamaan.ath.cx -- The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it can be an aesthetic experience much like composing poetry or music. -- Donald Knuth ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users
Re: [Chicken-users] struggling with macros
On 11 November 2012 13:30, Peter Bex peter@xs4all.nl wrote: On Sun, Nov 11, 2012 at 01:23:13PM +0100, Răzvan Rotaru wrote: Hi, Hi! I'm trying to write a simple javascript DSL, and got stuck in the macros :). (I'm coming from lisp macros) Take for example this one: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( ))] ) It is supposed to handle numbers and function calls, without building the parameter list in the function calls. It's doing this correctly, is it? Yes, behaviour is correct, but implementation is not complete, hence the next version of js-macro. You're trying to use MAP on a macro. That's not possible because macros are not first-class (this is true in Common Lisp as well). Well, essentially what I have here is a macro calling itself. How can I do that? I don't understand what you're trying to do here. I am trying to build a javascript DSL, similar to parenscript. The code above is very simple and should behave like this: (js 123) = 123 (js 123) = \123\ (js (1 2 3)) = 1(2, 3) The first two are primitives, the last is a function call. For simplicity, I ignored the comma that separates parameters in the function call. So the output I'm expecting from my code is actually: (js (1 2 3)) = 1(23) Răzvan ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users
Re: [Chicken-users] struggling with macros
On Sun, Nov 11, 2012 at 02:24:17PM +0100, Răzvan Rotaru wrote: On 11 November 2012 13:30, Peter Bex peter@xs4all.nl wrote: Yes, behaviour is correct, but implementation is not complete, hence the next version of js-macro. You're trying to use MAP on a macro. That's not possible because macros are not first-class (this is true in Common Lisp as well). Well, essentially what I have here is a macro calling itself. How can I do that? Generally, you can't. There are a few things you can do instead: - Expand to a new call to (js ...) for each of the elements. - Loop manually over the cdr inside the macro (maybe using map and an anonymous lambda). - Move the real conversion work into a procedure. This can be used by the macro, and the procedure can call itself. This is a bit tricky because you'll need to define the procedure in a begin-for-syntax block or put it in a separate module and require-for-syntax it. I am trying to build a javascript DSL, similar to parenscript. The code above is very simple and should behave like this: (js 123) = 123 (js 123) = \123\ (js (1 2 3)) = 1(2, 3) The first two are primitives, the last is a function call. For simplicity, I ignored the comma that separates parameters in the function call. So the output I'm expecting from my code is actually: (js (1 2 3)) = 1(23) I think that should be pretty easy. Cheers, Peter -- http://sjamaan.ath.cx -- The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it can be an aesthetic experience much like composing poetry or music. -- Donald Knuth ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users
Re: [Chicken-users] struggling with macros
Hi Răzvan, Just as a side-note: It may be a good idea to play around with your implementation as a normal function, and them wrap that in a macro once it's up on its feet. That way you can isolate problems with your implementation and problems with the macros. This approach is taken by the bind egg (see bind.scmhttp://bugs.call-cc.org/browser/release/4/bind/trunk/bind.scmand bind-translator.scmhttp://bugs.call-cc.org/browser/release/4/bind/trunk/bind-translator.scm). It could for example be setup like this: - js-transformer.scm ;; define a function js-transformer that does this: ;;(js-transformer 123) = 123 ;;(js-transformer 123) = \123\ ;;(js-transformer '(1 2 3)) = 1(2, 3) ;; note the quote! - js.scm ;; import js-transformer into syntax env (begin-for-syntax (include js-transformer.scm)) ;; or (import-for-syntax js-transformer.scm) if you have a module (I think) ;; define a macro that uses js-transformer at expansion-time (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (js-transform (cdr expr) K. On Sun, Nov 11, 2012 at 1:23 PM, Răzvan Rotaru razvan.rot...@gmail.comwrote: Hi, I'm trying to write a simple javascript DSL, and got stuck in the macros :). (I'm coming from lisp macros) Take for example this one: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( ))] ) It is supposed to handle numbers and function calls, without building the parameter list in the function calls. CSI (js 1) next=1 1 CSI (js (1 2 3)) next=(1 2 3) next=1 1() However, when trying to build the parameter list I get and error which I don't understand: (define-syntax js (ir-macro-transformer (lambda (expr inject compare) (let ((body (cdr expr)) (next (cadr expr))) (printf next=~a~n next) (cond [(string? next) (string-append \ next \)] [(number? next) (number-string next)] [(null? next) ] [(list? next) `(string-append (js ,(car next)) ( (apply string-append (map js ,(cdr next))) ))] ) CSI (js (1 2 3)) next=(1 2 3) next=1 Error: unbound variable: js [ inspect ] Restarts: 0: [ABORT] Return to SLIME's top level Backtrace: 0: eval [ more... ] (map248 js245 (2 3)) 1: eval [ more... ] (apply247 string-append246 (map248 js245 (2 3))) 2: eval [ more... ] (string-append246 (js245 1) ( (apply247 string-append246 (map248 js245 (2 3))) )) 3: syntax (2 3) 4: syntax (map248 js245 (2 3)) 5: syntax (apply247 string-append246 (map248 js245 (2 3))) 6: eval [ more... ] (number-string next) 7: eval [ more... ] (number? next) 8: eval [ more... ] (printf next=~a~n next) 9: eval [ more... ] (cadr expr) 10: eval [ more... ] (cdr expr) 11: syntax (js245 1) 12: syntax (string-append246 (js245 1) ( (apply247 string-append246 (map248 js245 (2 3))) )) 13: eval [ more... ] (cdr next) 14: eval [ more... ] (##sys#list (##core#quote map) (##core#quote js) (cdr next)) 15: eval [ more... ] (##sys#list (##core#quote apply) (##core#quote string-append) (##sys#list (##core#quote map) (##core#quote js) (cdr next))) So, my questions are: 1/ Why is js not bound in the second example? I also tried to use letrec-syntax but with same result. 2/ Are there other ways to achieve what I want? 3/ I also tried to use syntax-rules, but from what I understood this is not possible, because you can't execute arbitrary expressions (in this case a cond) at macroexpansion time. Am I right here? Thanks, Răzvan ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users ___ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users