Hi!
I'm not sure what expressions/terms should I use for my situation, but I'll try my best to explain it.
I have several functions combined under one ps:ps, and I'd like to create different code depending on my, let's call it debug variable. I have tried something like this:
(ps:ps
(defun my-function (some-var) (ps:lisp (when (= my-debug-level debug-level-of-this-code) (ps:ps (ps:chain console (log "works!!!"))))) (generate some fancy regular javascript code)))
Unfortunatelly, when the inner ps does its thing, it creates an string, which then outer ps just attaches (and escapes appropriately) as string, not as additional javascript code that is to be attached to the rest. Is it possible to do this, or do I have to rethink my code?
On 5/14/11, Slobodan Milnović slobodan.milnovic@gmail.com wrote:
Hi!
I'm not sure what expressions/terms should I use for my situation, but I'll try my best to explain it.
I have several functions combined under one ps:ps, and I'd like to create different code depending on my, let's call it debug variable. I have tried something like this:
(ps:ps
(defun my-function (some-var) (ps:lisp (when (= my-debug-level debug-level-of-this-code) (ps:ps (ps:chain console (log "works!!!"))))) (generate some fancy regular javascript code)))
Unfortunatelly, when the inner ps does its thing, it creates an string, which then outer ps just attaches (and escapes appropriately) as string, not as additional javascript code that is to be attached to the rest. Is it possible to do this, or do I have to rethink my code?
I can only think of this alternative:
(defpsmacro conditional-splice (test &body body) (when test `(progn ,@body)))
Using an older parenscript, because I don't have HEAD handy (though I don't think it matters much, and you still get the general idea):
CL-USER> (ps:ps (progn (a 1) (conditional-splice t (b 1) (c 2) (d 3)) (e 2))) "a(1); b(1); c(2); d(3); e(2);" CL-USER> (ps:ps (progn (a 1) (conditional-splice nil (b 1) (c 2) (d 3)) (e 2))) "a(1); e(2);" CL-USER>
That should be easily adapted to your use case, though it seems different to me because the lisp evaluation now happens during "macroexpansion time". In parenscript, "macroexpansion time" is intertwined with compilation, so you can think of it as being the same as "compile-time".
(Please correct me if I'm wrong here).
Yong.
2011/5/16 Theam Yong Chew senatorzergling@gmail.com:
I can only think of this alternative:
(defpsmacro conditional-splice (test &body body) (when test `(progn ,@body)))
Using an older parenscript, because I don't have HEAD handy (though I don't think it matters much, and you still get the general idea):
Actually, this is exactly what I need, thanks.
I thought about "interactive changing" of the debug and production mode, but, since I'm using weblocks, I have to reset session anyway to see the effects.
2011/5/16 Theam Yong Chew senatorzergling@gmail.com:
I can only think of this alternative:
(defpsmacro conditional-splice (test &body body) (when test `(progn ,@body)))
Hi,
I've tried to expand on this, but it seems that I'm missing some basic knowledge of lisp and parenscript macros. If I try something like this:
(ps:defpsmacro conditional-splice (cond1 cond2 &body body) (when (<= cond1 cond2) `(progn ,@body)))
(defvar first 2) (defvar second 3)
So, when I do this
(ps:ps (conditional-splice 2 3 4))
I get an ok response "4;"
but, when I do this
(ps:ps (conditional-splice first second 4))
then I get an error "The value FIRST is not of type REAL."
Well, I've tried with
(ps:ps (conditional-splice (ps:lisp first) (ps:lisp second) 4))
but I'm getting the same error.
So, what I'm missing is understanding in how to translate the value of the lisp variable into generated parenscript code. I've tried understanding parenscript documentation, but my guess is that this is something considered trivial knowledge when lisp/parenscript macros are involved (which I currently don't have).
Could anyone be so kind to point me to relevant documentation or try to give me an explanation of my error?
but, when I do this
(ps:ps (conditional-splice first second 4))
then I get an error "The value FIRST is not of type REAL."
Macros get their arguments unevaluated (quoted), so what's going on inside the macro is:
(<= 'first 'second)
Which is also why (ps:ps (conditional-splice (ps:lisp first) (ps:lisp second) 4)) doesn't work - you get (<= '(ps:lisp first) '(ps:lisp second))
You can try doing:
(ps:defpsmacro conditional-splice (cond1 cond2 &body body) (when (<= (eval cond1) (eval cond2)) `(progn ,@body)))
This will work because you've already defined first and second with DEFVAR, and eval picks up on whatever special variables are currently defined. The problem is it won't work for lexical variables.
In general writing macros like that is a very bad idea because you're introducing weird constraints on their arguments that have weird effects on what the macro expands to. That's hard to debug. The following pattern is better:
(defvar *expand-conditional-splice?* t)
(defpsmacro conditional-splice (&body body) (when *expand-conditional-splice?* `(progn ,@body)))
And then when you need to generate JavaScript:
(let ((*expand-conditional-splice?* (<= first second))) (ps:ps* ...code))
Note the ps:ps* there. ps:ps is itself a macro that translates PS code to JS at macro-expansion (compile) time, but in this example *expand-conditional-splice?* gets bound at run-time. You can use ps:ps, but then you have to be careful to set the value of *expand-conditional-splice?* correctly before your code gets compiled.
This might seem confusing at first, but the key thing is to learn what happens at compile-time, and what happens at run-time. On Lisp has a really good introduction to macros and how to think about them: http://www.paulgraham.com/onlisp.html
Vladimir
2011/6/1 Vladimir Sedach vsedach@gmail.com:
Note the ps:ps* there. ps:ps is itself a macro that translates PS code to JS at macro-expansion (compile) time, but in this example *expand-conditional-splice?* gets bound at run-time. You can use ps:ps, but then you have to be careful to set the value of *expand-conditional-splice?* correctly before your code gets compiled.
This might seem confusing at first, but the key thing is to learn what happens at compile-time, and what happens at run-time. On Lisp has a really good introduction to macros and how to think about them: http://www.paulgraham.com/onlisp.html
Thank you, it is much clearer now!
So, I'll have to rework my code to see where I can put ps:ps and where ps:ps*, because I'd prefer most of the code macro-expanded at compile time. I'm going currentyl through several lisp books, and I have decided to leave the onlisp for later when I get an better grasp on things, because when I first started with it, it became too advanced very fast for one that had no previous experience with lisp.
parenscript-devel@common-lisp.net