Here's why things do not Just Work reuse the same machinery for mustaches/sexprs recursively to handle subexpressions:
Every helper invocation (for helpers not explicitly listed
in knownHelpers
) must include a ternary else invocation
of helperMissing
in case the helper isn't found in
Handlebars.helpers
. Unless we fundamentally change the
way these strings of code are built up, this results in
long strings of logic for evaluating internal subexpressions
being duplicated between the found helper invocation and
helper missing invocation. Example:
Pseudo-code for evaluating {{equal (equal true true) true}}
bigassStringToCalculateInnerEqual =
if helpers.equal
helpers.equal(true, true, options)
else
helperMissing("equal", true, true, options)
if helpers.equal
helpers.equal(bigassStringToCalculateInnerEqual, true, options)
else
helperMissing("equal", bigassStringToCalculateInnerEqual, true, options)
When this is all stringified, you have megalong duplication between the various branches of code. Multiple nesting results in insanely long compiled teplate code.
The same options object needs to be provided to either the helper
or helperMissing
, so its saved to the options
var, and then
both the helper and helperMissing
invocation receive options
as
the last parameter.
But because the original code wasn't written to support subexpressions, the resulting compiled template code produced something like this whenever compiling subexpressions
options = {hash:{},data:data};
options = {hash:{},data:data};
options = {hash:{},data:data};
deeplyNestedRecursiveInvocationsOfHelperOrHelperMissing(...)
So each nested invocation added an options = ...
that clobbered
the previous. I already took a stab at moving the options =
to within the giant deeply nested string of invocations, but the problem
is that, unlike stack1
(which temporarily stores the helper being
invoked before getting replaced by an inner helper), the options
var
doesn't seem like it can be used multiple time for nested invocations.
Consider {{equal (doSomething) true}}
:
options = { stuff for equal }
- invoke equal
options = { stuff for doSomething }
- invoke doSomething
Jesus this is hard to explain. But press on I will.
(stack1 = helpers.equal), options = {options4equal}, stack1 ? stack1.call(d, (internalStuff), options) : helperMissing('doSomething', (internalStuff), options)
internalStuff ->
(stack1 = helpers.doSomething), options = {options4doSomething}, stack1 ? stack1.call(d, options) : helperMissing('doSomething', options)
Basically, we have this neato way for reusing the stack1
variable
that's incompatible with storing the options
in a single variable
when we have nested subexpressions, because the first options
will be set to
options = {options4Equal}
and then on the inner nested expression evaluation it sets
options = {options4doSomething}
Which overwrites the previous options
, so the options that
ends up getting passed to equal
is options4doSomething
,
which is obviously bad.
I don't know. I need to think on it. This seems like some elementary shit for anyone who's implemented a Lisp.