1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Added safe soaking on non-existent variables.

This commit is contained in:
Tim Jones 2010-05-05 21:58:48 +12:00
parent d0d0fa4d10
commit 0b3bb66708
3 changed files with 40 additions and 17 deletions

View file

@ -425,34 +425,46 @@
ValueNode.prototype.is_statement = function is_statement() {
return this.base.is_statement && this.base.is_statement() && !this.has_properties();
};
// Works out if the value is the start of a chain.
ValueNode.prototype.is_start = function is_start(o) {
var node;
if (this === o.chain_root && this.properties[0] instanceof AccessorNode) {
return true;
}
node = o.chain_root.base || o.chain_root.variable;
while (node instanceof CallNode) {
node = node.variable;
}
return node === this;
};
// We compile a value to JavaScript by compiling and joining each property.
// Things get much more insteresting if the chain of properties has *soak*
// operators `?.` interspersed. Then we have to take care not to accidentally
// evaluate a anything twice when building the soak chain.
ValueNode.prototype.compile_node = function compile_node(o) {
var _b, _c, _d, baseline, complete, only, op, part, prop, props, temp;
var _b, _c, baseline, complete, i, only, op, part, prop, props, temp;
only = del(o, 'only_first');
op = del(o, 'operation');
props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties;
if (!(o.chain_root)) {
o.chain_root = this;
}
o.chain_root = o.chain_root || this;
baseline = this.base.compile(o);
if (this.base instanceof ObjectNode && this.has_properties()) {
baseline = ("(" + baseline + ")");
}
complete = (this.last = baseline);
_c = props;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
prop = _c[_b];
_b = props;
for (i = 0, _c = _b.length; i < _c; i++) {
prop = _b[i];
this.source = baseline;
if (prop.soak_node) {
if (this.base instanceof CallNode && prop === props[0]) {
if (this.base instanceof CallNode && i === 0) {
temp = o.scope.free_variable();
complete = ("(" + temp + " = " + complete + ")" + this.SOAK) + (baseline = temp + prop.compile(o));
} else {
complete = complete + this.SOAK + (baseline += prop.compile(o));
complete = ("(" + (baseline = temp) + " = (" + complete + "))");
}
if (i === 0 && this.is_start(o)) {
complete = ("typeof " + complete + " === \"undefined\" || " + baseline);
}
complete += this.SOAK + (baseline += prop.compile(o));
} else {
part = prop.compile(o);
baseline += part;

View file

@ -298,6 +298,13 @@ exports.ValueNode: class ValueNode extends BaseNode
# Values are considered to be statements if their base is a statement.
is_statement: ->
@base.is_statement and @base.is_statement() and not @has_properties()
# Works out if the value is the start of a chain.
is_start: (o) ->
return true if this is o.chain_root and @properties[0] instanceof AccessorNode
node: o.chain_root.base or o.chain_root.variable
while node instanceof CallNode then node: node.variable
node is this
# We compile a value to JavaScript by compiling and joining each property.
# Things get much more insteresting if the chain of properties has *soak*
@ -307,19 +314,19 @@ exports.ValueNode: class ValueNode extends BaseNode
only: del(o, 'only_first')
op: del(o, 'operation')
props: if only then @properties[0...@properties.length - 1] else @properties
o.chain_root: this unless o.chain_root
o.chain_root: or this
baseline: @base.compile o
baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties()
complete: @last: baseline
for prop in props
for prop, i in props
@source: baseline
if prop.soak_node
if @base instanceof CallNode and prop is props[0]
if @base instanceof CallNode and i is 0
temp: o.scope.free_variable()
complete: "($temp = $complete)$@SOAK" + (baseline: temp + prop.compile(o))
else
complete: complete + @SOAK + (baseline: + prop.compile(o))
complete: "(${ baseline: temp } = ($complete))"
complete: "typeof $complete === \"undefined\" || $baseline" if i is 0 and @is_start(o)
complete: + @SOAK + (baseline: + prop.compile(o))
else
part: prop.compile(o)
baseline: + part

View file

@ -74,3 +74,7 @@ ok result is '10'
result: not value?.property?
ok result
# Safely calls values off of non-existent variables.
result: nothing?.value
ok result is undefined