No way to get gensymmed identifiers without introducing closure
Created by: jhusain
I'm confused about something. The first thing I tried was a simple foreach macro. The forEach function is too slow on some of our devices so we continually write out counting for loops.
macro foreach { case ($name:ident $collection) $body => { var arr = $collection, counter, length; for(counter = 0, length = arr.length; counter < length; counter++) { $name = arr[counter]; $body } } }
foreach (x [3, 4, 5]) { console.log(x); }
// generates...
var arr = [ 3, 4, 5 ], counter, length; for (counter = 0, length = arr.length; counter < length; counter++) { x = arr[counter]; { console.log(x); } }
Pretty darn good. An extra scope being introduced for the body, but otherwise easy and nice. The problem came up when I tried to nest foreach's. My variables weren't gensymmed.
foreach (x [3, 4, 5]) { foreach (y [3, 4, 5]) { console.log(x + y); } }
// generates...
var arr = [ 3, 4, 5 ], counter, length; for (counter = 0, length = arr.length; counter < length; counter++) { x = arr[counter]; { var arr = [ 3, 4, 5 ], counter, length; for (counter = 0, length = arr.length; counter < length; counter++) { y = arr[counter]; { console.log(x + y); } } } }
Yikes! I looked at other examples and found that sweetJS looked for a new function scope as an indication that variables should be gensymmed. I thought this very logical...until I realized the function made it's way into the generated code.
macro foreach { case ($name:ident $collection) $body => { (function(arr,counter,length) { arr = $collection; for(counter = 0, length = arr.length; counter < length; counter++) { $name = arr[counter]; $body } }) } }
foreach (x [3, 4, 5]) { console.log(x) }
// generates...
(function (arr$53, counter$54, length$55) { arr$53 = [ 3, 4, 5 ]; for (counter$54 = 0, length$55 = arr$53.length; counter$54 < length$55; counter$54++) { x = arr$53[counter$54]; { console.log(x); } } });
I'm probably missing something obvious here, but it seems to me that when I create a function scope I don't need gensyms because javascript creates a new scope. Any outer variables with the same names will be hidden by the new identifiers. It would be much more useful for me if var's within the macro and the in-lined body were all gensymed.
I'm specifically trying to avoid introducing a function call and scope for performance reasons. If I were going to do that, I could simply do this:
[1,2,3].forEach(function(item) { console.log(item); })
Thanks,
Jafar