Wrapping all soaked chains that are involved in operations.

This commit is contained in:
Tim Jones
2010-05-04 01:04:26 +12:00
committed by Jeremy Ashkenas
parent 4d935efd09
commit ac05f62f2f
2 changed files with 57 additions and 35 deletions

View File

@@ -71,8 +71,11 @@
var closure, top; var closure, top;
this.options = merge(o || {}); this.options = merge(o || {});
this.tab = o.indent; this.tab = o.indent;
if (!(this instanceof ValueNode)) { if (!(this instanceof ValueNode || this instanceof CallNode)) {
del(this.options, 'operation'); del(this.options, 'operation');
if (!(this instanceof AccessorNode || this instanceof IndexNode)) {
del(this.options, 'chain_root');
}
} }
top = this.top_sensitive() ? this.options.top : del(this.options, 'top'); top = this.top_sensitive() ? this.options.top : del(this.options, 'top');
closure = this.is_statement() && !this.is_pure_statement() && !top && !this.options.as_statement && !(this instanceof CommentNode) && !this.contains_pure_statement(); closure = this.is_statement() && !this.is_pure_statement() && !top && !this.options.as_statement && !(this instanceof CommentNode) && !this.contains_pure_statement();
@@ -427,11 +430,13 @@
// operators `?.` interspersed. Then we have to take care not to accidentally // operators `?.` interspersed. Then we have to take care not to accidentally
// evaluate a anything twice when building the soak chain. // evaluate a anything twice when building the soak chain.
ValueNode.prototype.compile_node = function compile_node(o) { ValueNode.prototype.compile_node = function compile_node(o) {
var _b, _c, _d, baseline, complete, only, op, part, prop, props, soaked, temp; var _b, _c, _d, baseline, complete, only, op, part, prop, props, temp;
soaked = false;
only = del(o, 'only_first'); only = del(o, 'only_first');
op = del(o, 'operation'); op = del(o, 'operation');
props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties; props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties;
if (!(o.chain_root)) {
o.chain_root = this;
}
baseline = this.base.compile(o); baseline = this.base.compile(o);
if (this.base instanceof ObjectNode && this.has_properties()) { if (this.base instanceof ObjectNode && this.has_properties()) {
baseline = ("(" + baseline + ")"); baseline = ("(" + baseline + ")");
@@ -442,7 +447,6 @@
prop = _c[_b]; prop = _c[_b];
this.source = baseline; this.source = baseline;
if (prop.soak_node) { if (prop.soak_node) {
soaked = true;
if (this.base instanceof CallNode && prop === props[0]) { if (this.base instanceof CallNode && prop === props[0]) {
temp = o.scope.free_variable(); temp = o.scope.free_variable();
complete = ("(" + temp + " = " + complete + ")" + this.SOAK) + (baseline = temp + prop.compile(o)); complete = ("(" + temp + " = " + complete + ")" + this.SOAK) + (baseline = temp + prop.compile(o));
@@ -456,7 +460,8 @@
this.last = part; this.last = part;
} }
} }
if (op && soaked) { del(o, 'chain_root');
if (op && this.wrapped) {
return "(" + complete + ")"; return "(" + complete + ")";
} else { } else {
return complete; return complete;
@@ -525,26 +530,32 @@
}; };
// Compile a vanilla function call. // Compile a vanilla function call.
CallNode.prototype.compile_node = function compile_node(o) { CallNode.prototype.compile_node = function compile_node(o) {
var _b, _c, _d, _e, _f, _g, _h, arg, args; var _b, _c, _d, _e, _f, _g, _h, arg, args, compilation;
if (!(o.chain_root)) {
o.chain_root = this;
}
_c = this.args; _c = this.args;
for (_b = 0, _d = _c.length; _b < _d; _b++) { for (_b = 0, _d = _c.length; _b < _d; _b++) {
arg = _c[_b]; arg = _c[_b];
if (arg instanceof SplatNode) { arg instanceof SplatNode ? (compilation = this.compile_splat(o)) : null;
return this.compile_splat(o);
}
} }
args = (function() { if (!(compilation)) {
_e = []; _g = this.args; args = (function() {
for (_f = 0, _h = _g.length; _f < _h; _f++) { _e = []; _g = this.args;
arg = _g[_f]; for (_f = 0, _h = _g.length; _f < _h; _f++) {
_e.push(arg.compile(o)); arg = _g[_f];
} _e.push(arg.compile(o));
return _e; }
}).call(this).join(', '); return _e;
if (this.is_super) { }).call(this).join(', ');
return this.compile_super(args, o); compilation = this.is_super ? this.compile_super(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + args + ")");
}
del(o, 'chain_root');
if (o.operation && this.wrapped) {
return "(" + compilation + ")";
} else {
return compilation;
} }
return "" + (this.prefix()) + (this.variable.compile(o)) + "(" + args + ")";
}; };
// `super()` is converted into a call against the superclass's implementation // `super()` is converted into a call against the superclass's implementation
// of the current function. // of the current function.
@@ -628,6 +639,7 @@
__extends(AccessorNode, BaseNode); __extends(AccessorNode, BaseNode);
AccessorNode.prototype.compile_node = function compile_node(o) { AccessorNode.prototype.compile_node = function compile_node(o) {
var proto_part; var proto_part;
o.chain_root.wrapped = o.chain_root.wrapped || this.soak_node;
proto_part = this.prototype ? 'prototype.' : ''; proto_part = this.prototype ? 'prototype.' : '';
return "." + proto_part + (this.name.compile(o)); return "." + proto_part + (this.name.compile(o));
}; };
@@ -644,6 +656,7 @@
__extends(IndexNode, BaseNode); __extends(IndexNode, BaseNode);
IndexNode.prototype.compile_node = function compile_node(o) { IndexNode.prototype.compile_node = function compile_node(o) {
var idx; var idx;
o.chain_root.wrapped = this.soak_node;
idx = this.index.compile(o); idx = this.index.compile(o);
return "[" + idx + "]"; return "[" + idx + "]";
}; };

View File

@@ -50,7 +50,9 @@ exports.BaseNode: class BaseNode
compile: (o) -> compile: (o) ->
@options: merge o or {} @options: merge o or {}
@tab: o.indent @tab: o.indent
del @options, 'operation' unless this instanceof ValueNode unless this instanceof ValueNode or this instanceof CallNode
del @options, 'operation'
del @options, 'chain_root' unless this instanceof AccessorNode or this instanceof IndexNode
top: if @top_sensitive() then @options.top else del @options, 'top' top: if @top_sensitive() then @options.top else del @options, 'top'
closure: @is_statement() and not @is_pure_statement() and not top and closure: @is_statement() and not @is_pure_statement() and not top and
not @options.as_statement and not (this instanceof CommentNode) and not @options.as_statement and not (this instanceof CommentNode) and
@@ -302,18 +304,17 @@ exports.ValueNode: class ValueNode extends BaseNode
# operators `?.` interspersed. Then we have to take care not to accidentally # operators `?.` interspersed. Then we have to take care not to accidentally
# evaluate a anything twice when building the soak chain. # evaluate a anything twice when building the soak chain.
compile_node: (o) -> compile_node: (o) ->
soaked: false only: del(o, 'only_first')
only: del(o, 'only_first') op: del(o, 'operation')
op: del(o, 'operation') props: if only then @properties[0...@properties.length - 1] else @properties
props: if only then @properties[0...@properties.length - 1] else @properties o.chain_root: this unless o.chain_root
baseline: @base.compile o baseline: @base.compile o
baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties() baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties()
complete: @last: baseline complete: @last: baseline
for prop in props for prop in props
@source: baseline @source: baseline
if prop.soak_node if prop.soak_node
soaked: true
if @base instanceof CallNode and prop is props[0] if @base instanceof CallNode and prop is props[0]
temp: o.scope.free_variable() temp: o.scope.free_variable()
complete: "($temp = $complete)$@SOAK" + (baseline: temp + prop.compile(o)) complete: "($temp = $complete)$@SOAK" + (baseline: temp + prop.compile(o))
@@ -324,8 +325,10 @@ exports.ValueNode: class ValueNode extends BaseNode
baseline: + part baseline: + part
complete: + part complete: + part
@last: part @last: part
del o, 'chain_root'
if op and soaked then "($complete)" else complete if op and @wrapped then "($complete)" else complete
#### CommentNode #### CommentNode
@@ -377,11 +380,15 @@ exports.CallNode: class CallNode extends BaseNode
# Compile a vanilla function call. # Compile a vanilla function call.
compile_node: (o) -> compile_node: (o) ->
for arg in @args o.chain_root: this unless o.chain_root
return @compile_splat(o) if arg instanceof SplatNode for arg in @args when arg instanceof SplatNode
args: (arg.compile(o) for arg in @args).join(', ') compilation: @compile_splat(o)
return @compile_super(args, o) if @is_super unless compilation
"${@prefix()}${@variable.compile(o)}($args)" args: (arg.compile(o) for arg in @args).join(', ')
compilation: if @is_super then @compile_super(args, o)
else "${@prefix()}${@variable.compile(o)}($args)"
del o, 'chain_root'
if o.operation and @wrapped then "($compilation)" else compilation
# `super()` is converted into a call against the superclass's implementation # `super()` is converted into a call against the superclass's implementation
# of the current function. # of the current function.
@@ -449,6 +456,7 @@ exports.AccessorNode: class AccessorNode extends BaseNode
this this
compile_node: (o) -> compile_node: (o) ->
o.chain_root.wrapped: or @soak_node
proto_part: if @prototype then 'prototype.' else '' proto_part: if @prototype then 'prototype.' else ''
".$proto_part${@name.compile(o)}" ".$proto_part${@name.compile(o)}"
@@ -462,6 +470,7 @@ exports.IndexNode: class IndexNode extends BaseNode
@soak_node: tag is 'soak' @soak_node: tag is 'soak'
compile_node: (o) -> compile_node: (o) ->
o.chain_root.wrapped: @soak_node
idx: @index.compile o idx: @index.compile o
"[$idx]" "[$idx]"