When you're introducing a new identifier, and it's being bound to an expression
of the form (do ... x#)
or (let [...] x#)
, the x#
could be replaced with
the new identifier being introduced. This would reduce the number of gensyms in
generated code.
See the following example:
(local x
(?. a b c)
fennel --complile test.fnl
local x
do
local t_1_ = a
if (nil ~= t_1_) then
t_1_ = t_1_[b]
else
end
if (nil ~= t_1_) then
t_1_ = t_1_[c]
else
end
x = t_1_
end
return nil
local x
do
x = a
if (nil ~= x) then
x = x[b]
else
end
if (nil ~= x) then
x = x[c]
else
end
end
return nil
I suspect this would require a relatively large refactor of the compiler to accomplish.
This appears ~22 times in the fennel compendium, but I would like to believe it is undercounted as the fennel compendium games seem less likely to use macros like (icollect) and (doto), which are the main sources of this category of gensym:
(local x (doto (foo) (bar)))
(local x (icollect ...))
(local x (?. a b c d e)
I counted these using the regular expression ^ *[-a-z0-9?]+ = [a-z]*_[0-9]+_(auto)?\n *end
,
manually skipping places where the gensym is a function, as in cases like (local x (fn [...] ...)
.
I don't understand how this would work. It seems like you're suggesting that macros should have access to see what target their return value is being assigned to? I could see this working with some specials, but with a macro it seems impossible. Maybe I'm misunderstanding.
In my head, I'm imagining something like:
- macros get expanded
- compiler is in SPECIALS.let
- let* notices "oh hey the thing that I return is a gensym that I declare"
- let* somehow verifies that the target is a new variable being declared, so that its safe to write dummy intermediate values to the target. In all of my examples, the target is a new variable being declared, so it is safe.
- let* tweaks the scope manglings so that assignments to the gensym point directly to the target.
- then, continue compilation
- at the end, skip emitting the assignment from the gensym to the target
The target in the lua blocks above would be
x
and the gensym ist_1_
So I'm proposing this only for the
let
(and maybe thedo
) special. I think all the mentioned macros expand tolet
.