-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for subexpressions #690
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -244,9 +244,6 @@ JavaScriptCompiler.prototype = { | |
var current = this.topStack(); | ||
params.splice(1, 0, current); | ||
|
||
// Use the options value generated from the invocation | ||
params[params.length-1] = 'options'; | ||
|
||
this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); | ||
}, | ||
|
||
|
@@ -398,19 +395,23 @@ JavaScriptCompiler.prototype = { | |
|
||
this.pushString(type); | ||
|
||
if (typeof string === 'string') { | ||
this.pushString(string); | ||
} else { | ||
this.pushStackLiteral(string); | ||
// If it's a subexpression, the string result | ||
// will be pushed after this opcode. | ||
if (type !== 'sexpr') { | ||
if (typeof string === 'string') { | ||
this.pushString(string); | ||
} else { | ||
this.pushStackLiteral(string); | ||
} | ||
} | ||
}, | ||
|
||
emptyHash: function() { | ||
this.pushStackLiteral('{}'); | ||
|
||
if (this.options.stringParams) { | ||
this.register('hashTypes', '{}'); | ||
this.register('hashContexts', '{}'); | ||
this.push('{}'); // hashContexts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are registers still used after removing this and the other references? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not for hashTypes/hashContexts |
||
this.push('{}'); // hashTypes | ||
} | ||
}, | ||
pushHash: function() { | ||
|
@@ -421,9 +422,10 @@ JavaScriptCompiler.prototype = { | |
this.hash = undefined; | ||
|
||
if (this.options.stringParams) { | ||
this.register('hashContexts', '{' + hash.contexts.join(',') + '}'); | ||
this.register('hashTypes', '{' + hash.types.join(',') + '}'); | ||
this.push('{' + hash.contexts.join(',') + '}'); | ||
this.push('{' + hash.types.join(',') + '}'); | ||
} | ||
|
||
this.push('{\n ' + hash.values.join(',\n ') + '\n }'); | ||
}, | ||
|
||
|
@@ -526,7 +528,7 @@ JavaScriptCompiler.prototype = { | |
invokeAmbiguous: function(name, helperCall) { | ||
this.context.aliases.functionType = '"function"'; | ||
|
||
this.pushStackLiteral('{}'); // Hash value | ||
this.emptyHash(); | ||
var helper = this.setupHelper(0, name, helperCall); | ||
|
||
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); | ||
|
@@ -805,6 +807,11 @@ JavaScriptCompiler.prototype = { | |
|
||
options.push("hash:" + this.popStack()); | ||
|
||
if (this.options.stringParams) { | ||
options.push("hashTypes:" + this.popStack()); | ||
options.push("hashContexts:" + this.popStack()); | ||
} | ||
|
||
inverse = this.popStack(); | ||
program = this.popStack(); | ||
|
||
|
@@ -838,22 +845,13 @@ JavaScriptCompiler.prototype = { | |
if (this.options.stringParams) { | ||
options.push("contexts:[" + contexts.join(",") + "]"); | ||
options.push("types:[" + types.join(",") + "]"); | ||
options.push("hashContexts:hashContexts"); | ||
options.push("hashTypes:hashTypes"); | ||
} | ||
|
||
if(this.options.data) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the useRegister true case no longer used/needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, this is one of the things that had to be inlined to support subexpressions. There shouldn't be any performance impac (the same number of objects are being evaluated/created), just that the templates will be just slightly larger. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it not possible to use a stack value or other means to remove the duplicated values? I worry about anything that adds bytes to the wire but that might be unfounded as gzip would ideally remove a lot of the weight of purely duplicated code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I explored some options but this was by far the simplest/most efficient. The stack var optimization that prevented us from needing multiple stack vars when invoking helpers is no longer available to us since invoking a helper means invoking its 0-N subexpressions that would also need stack vars. It's really hard to explain this bit of it but I'm fairly certain this is as simple/efficient as it's gonna get, and I think you're correct about gzip. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't think of this until now. What happens if you have subexpressions on the hash? Will that logic be duplicated or will it utilize a stack reference to lookup the value? That could be very costly if multiple expressions are nested. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have tests for subexpressions on the hash, and yes, nested subexpressions causes a lot of duplication. Take a look at this gist: https://gist.github.com/machty/2091198e5cba9fe0163f On here I voiced some concerns about duplication, getting rid of stack vars, etc, and Yehuda seemed pretty ok with it given that gzip is a thing. (Though it still startled me at first) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fine with merging this for now, taking the gzip argument but I am going to take a crack at simplifying it post merge. Another set of eyes, etc :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be wonderful |
||
options.push("data:data"); | ||
} | ||
|
||
options = "{" + options.join(",") + "}"; | ||
if (useRegister) { | ||
this.register('options', options); | ||
params.push('options'); | ||
} else { | ||
params.push(options); | ||
} | ||
return params.join(", "); | ||
params.push("{" + options.join(",") + "}"); | ||
} | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer returning the params? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No one used the return value. Should I just keep it as it was? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, didn't realize that it wasn't used until after I made the comment. It's not an API method and not used so we shouldn't waste cycles/bandwidth with it. |
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -142,4 +142,20 @@ describe('string params mode', function() { | |
|
||
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot", "Proper context variable output"); | ||
}); | ||
|
||
it("with nested block ambiguous", function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this test doing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It adds coverage to something that broke during my code reorg, specific to ambiguous block helper invocations only in string mode. Is there a better name or something more meaningful I could put in the description? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine, I wasn't sure that it was related to string mode etc. For my own curiosity, how was the code failing when it broke? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Illegal JS code was generated in the template with |
||
var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true}); | ||
|
||
var helpers = { | ||
with: function(options) { | ||
return "WITH"; | ||
}, | ||
view: function() { | ||
return "VIEW"; | ||
} | ||
}; | ||
|
||
var result = template({}, {helpers: helpers}); | ||
equals(result, "WITH"); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer passing options object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another thing that was inlined