mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 03:21:20 -05:00
Existence checks on functions now supported.
This commit is contained in:
@@ -265,17 +265,22 @@
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
Invocation: [
|
Invocation: [
|
||||||
o("Value Arguments", function() {
|
o("Value OptFuncExist Arguments", function() {
|
||||||
return new CallNode($1, $2);
|
return new CallNode($1, $3, $2);
|
||||||
}), o("Invocation Arguments", function() {
|
}), o("Invocation OptFuncExist Arguments", function() {
|
||||||
return new CallNode($1, $2);
|
return new CallNode($1, $3, $2);
|
||||||
|
})
|
||||||
|
],
|
||||||
|
OptFuncExist: [
|
||||||
|
o("", function() {
|
||||||
|
return false;
|
||||||
|
}), o("FUNC_EXIST", function() {
|
||||||
|
return true;
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
Arguments: [
|
Arguments: [
|
||||||
o("CALL_START ArgList OptComma CALL_END", function() {
|
o("CALL_START ArgList OptComma CALL_END", function() {
|
||||||
return $2;
|
return $2;
|
||||||
}), o("FUNC_EXIST CALL_START ArgList OptComma CALL_END", function() {
|
|
||||||
return $3;
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
Super: [
|
Super: [
|
||||||
|
|||||||
41
lib/nodes.js
41
lib/nodes.js
@@ -443,13 +443,15 @@
|
|||||||
return CommentNode;
|
return CommentNode;
|
||||||
})();
|
})();
|
||||||
exports.CallNode = (function() {
|
exports.CallNode = (function() {
|
||||||
CallNode = function(variable, _b) {
|
CallNode = function(variable, _b, _c) {
|
||||||
|
this.exist = _c;
|
||||||
this.args = _b;
|
this.args = _b;
|
||||||
CallNode.__super__.constructor.call(this);
|
CallNode.__super__.constructor.call(this);
|
||||||
this.isNew = false;
|
this.isNew = false;
|
||||||
this.isSuper = variable === 'super';
|
this.isSuper = variable === 'super';
|
||||||
this.variable = this.isSuper ? null : variable;
|
this.variable = this.isSuper ? null : variable;
|
||||||
this.args || (this.args = []);
|
this.args || (this.args = []);
|
||||||
|
this.first = (this.last = '');
|
||||||
this.compileSplatArguments = function(o) {
|
this.compileSplatArguments = function(o) {
|
||||||
return SplatNode.compileSplattedArray.call(this, this.args, o);
|
return SplatNode.compileSplattedArray.call(this, this.args, o);
|
||||||
};
|
};
|
||||||
@@ -479,30 +481,41 @@
|
|||||||
})());
|
})());
|
||||||
};
|
};
|
||||||
CallNode.prototype.compileNode = function(o) {
|
CallNode.prototype.compileNode = function(o) {
|
||||||
var _b, _c, _d, _e, _f, _g, _h, arg, args, compilation;
|
var _b, _c, _d, _e, _f, _g, _h, _i, arg, args, compilation;
|
||||||
if (!(o.chainRoot)) {
|
if (!(o.chainRoot)) {
|
||||||
o.chainRoot = this;
|
o.chainRoot = this;
|
||||||
}
|
}
|
||||||
_c = this.args;
|
if (this.exist) {
|
||||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
_b = this.variable.compileReference(o, {
|
||||||
arg = _c[_b];
|
precompile: true
|
||||||
|
});
|
||||||
|
this.first = _b[0];
|
||||||
|
this.meth = _b[1];
|
||||||
|
this.first = ("typeof " + (this.first) + " === \"function\" ? ");
|
||||||
|
this.last = " : null";
|
||||||
|
} else if (this.variable) {
|
||||||
|
this.meth = this.variable.compile(o);
|
||||||
|
}
|
||||||
|
_d = this.args;
|
||||||
|
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||||
|
arg = _d[_c];
|
||||||
if (arg instanceof SplatNode) {
|
if (arg instanceof SplatNode) {
|
||||||
compilation = this.compileSplat(o);
|
compilation = this.compileSplat(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!compilation) {
|
if (!compilation) {
|
||||||
args = (function() {
|
args = (function() {
|
||||||
_e = []; _g = this.args;
|
_f = []; _h = this.args;
|
||||||
for (_f = 0, _h = _g.length; _f < _h; _f++) {
|
for (_g = 0, _i = _h.length; _g < _i; _g++) {
|
||||||
arg = _g[_f];
|
arg = _h[_g];
|
||||||
_e.push((function() {
|
_f.push((function() {
|
||||||
arg.parenthetical = true;
|
arg.parenthetical = true;
|
||||||
return arg.compile(o);
|
return arg.compile(o);
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
return _e;
|
return _f;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
compilation = this.isSuper ? this.compileSuper(args.join(', '), o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + (args.join(', ')) + ")");
|
compilation = this.isSuper ? this.compileSuper(args.join(', '), o) : ("" + (this.first) + (this.prefix()) + (this.meth) + "(" + (args.join(', ')) + ")" + (this.last));
|
||||||
}
|
}
|
||||||
return compilation;
|
return compilation;
|
||||||
};
|
};
|
||||||
@@ -511,7 +524,7 @@
|
|||||||
};
|
};
|
||||||
CallNode.prototype.compileSplat = function(o) {
|
CallNode.prototype.compileSplat = function(o) {
|
||||||
var meth, obj, temp;
|
var meth, obj, temp;
|
||||||
meth = this.variable ? this.variable.compile(o) : this.superReference(o);
|
meth = this.meth || this.superReference(o);
|
||||||
obj = this.variable && this.variable.source || 'this';
|
obj = this.variable && this.variable.source || 'this';
|
||||||
if (obj.match(/\(/)) {
|
if (obj.match(/\(/)) {
|
||||||
temp = o.scope.freeVariable();
|
temp = o.scope.freeVariable();
|
||||||
@@ -520,9 +533,9 @@
|
|||||||
}
|
}
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
utility('extends');
|
utility('extends');
|
||||||
return "(function() {\n" + (this.idt(1)) + "var ctor = function(){};\n" + (this.idt(1)) + "__extends(ctor, " + (meth) + ");\n" + (this.idt(1)) + "return " + (meth) + ".apply(new ctor, " + (this.compileSplatArguments(o)) + ");\n" + (this.tab) + "}).call(this)";
|
return "" + (this.first) + "(function() {\n" + (this.idt(1)) + "var ctor = function(){};\n" + (this.idt(1)) + "__extends(ctor, " + (meth) + ");\n" + (this.idt(1)) + "return " + (meth) + ".apply(new ctor, " + (this.compileSplatArguments(o)) + ");\n" + (this.tab) + "}).call(this)" + (this.last);
|
||||||
} else {
|
} else {
|
||||||
return "" + (this.prefix()) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")";
|
return "" + (this.first) + (this.prefix()) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")" + (this.last);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return CallNode;
|
return CallNode;
|
||||||
|
|||||||
208
lib/parser.js
208
lib/parser.js
File diff suppressed because one or more lines are too long
@@ -312,14 +312,19 @@ grammar =
|
|||||||
|
|
||||||
# Ordinary function invocation, or a chained series of calls.
|
# Ordinary function invocation, or a chained series of calls.
|
||||||
Invocation: [
|
Invocation: [
|
||||||
o "Value Arguments", -> new CallNode $1, $2
|
o "Value OptFuncExist Arguments", -> new CallNode $1, $3, $2
|
||||||
o "Invocation Arguments", -> new CallNode $1, $2
|
o "Invocation OptFuncExist Arguments", -> new CallNode $1, $3, $2
|
||||||
|
]
|
||||||
|
|
||||||
|
# An optional existence check on a function.
|
||||||
|
OptFuncExist: [
|
||||||
|
o "", -> no
|
||||||
|
o "FUNC_EXIST", -> yes
|
||||||
]
|
]
|
||||||
|
|
||||||
# The list of arguments to a function call.
|
# The list of arguments to a function call.
|
||||||
Arguments: [
|
Arguments: [
|
||||||
o "CALL_START ArgList OptComma CALL_END", -> $2
|
o "CALL_START ArgList OptComma CALL_END", -> $2
|
||||||
o "FUNC_EXIST CALL_START ArgList OptComma CALL_END", -> $3
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Calling super.
|
# Calling super.
|
||||||
|
|||||||
@@ -410,12 +410,13 @@ exports.CallNode = class CallNode extends BaseNode
|
|||||||
class: 'CallNode'
|
class: 'CallNode'
|
||||||
children: ['variable', 'args']
|
children: ['variable', 'args']
|
||||||
|
|
||||||
constructor: (variable, @args) ->
|
constructor: (variable, @args, @exist) ->
|
||||||
super()
|
super()
|
||||||
@isNew = false
|
@isNew = false
|
||||||
@isSuper = variable is 'super'
|
@isSuper = variable is 'super'
|
||||||
@variable = if @isSuper then null else variable
|
@variable = if @isSuper then null else variable
|
||||||
@args or= []
|
@args or= []
|
||||||
|
@first = @last = ''
|
||||||
@compileSplatArguments = (o) ->
|
@compileSplatArguments = (o) ->
|
||||||
SplatNode.compileSplattedArray.call(this, @args, o)
|
SplatNode.compileSplattedArray.call(this, @args, o)
|
||||||
|
|
||||||
@@ -439,6 +440,11 @@ exports.CallNode = class CallNode extends BaseNode
|
|||||||
# Compile a vanilla function call.
|
# Compile a vanilla function call.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
o.chainRoot = this unless o.chainRoot
|
o.chainRoot = this unless o.chainRoot
|
||||||
|
if @exist
|
||||||
|
[@first, @meth] = @variable.compileReference o, precompile: yes
|
||||||
|
@first = "typeof #{@first} === \"function\" ? "
|
||||||
|
@last = " : null"
|
||||||
|
else if @variable then @meth = @variable.compile o
|
||||||
for arg in @args when arg instanceof SplatNode
|
for arg in @args when arg instanceof SplatNode
|
||||||
compilation = @compileSplat(o)
|
compilation = @compileSplat(o)
|
||||||
if not compilation
|
if not compilation
|
||||||
@@ -448,7 +454,7 @@ exports.CallNode = class CallNode extends BaseNode
|
|||||||
compilation = if @isSuper
|
compilation = if @isSuper
|
||||||
@compileSuper(args.join(', '), o)
|
@compileSuper(args.join(', '), o)
|
||||||
else
|
else
|
||||||
"#{@prefix()}#{@variable.compile(o)}(#{ args.join(', ') })"
|
"#{@first}#{@prefix()}#{@meth}(#{ args.join(', ') })#{@last}"
|
||||||
compilation
|
compilation
|
||||||
|
|
||||||
# `super()` is converted into a call against the superclass's implementation
|
# `super()` is converted into a call against the superclass's implementation
|
||||||
@@ -461,23 +467,23 @@ exports.CallNode = class CallNode extends BaseNode
|
|||||||
# If it's a constructor, then things get real tricky. We have to inject an
|
# If it's a constructor, then things get real tricky. We have to inject an
|
||||||
# inner constructor in order to be able to pass the varargs.
|
# inner constructor in order to be able to pass the varargs.
|
||||||
compileSplat: (o) ->
|
compileSplat: (o) ->
|
||||||
meth = if @variable then @variable.compile(o) else @superReference(o)
|
meth = @meth or @superReference(o)
|
||||||
obj = @variable and @variable.source or 'this'
|
obj = @variable and @variable.source or 'this'
|
||||||
if obj.match(/\(/)
|
if obj.match(/\(/)
|
||||||
temp = o.scope.freeVariable()
|
temp = o.scope.freeVariable()
|
||||||
obj = temp
|
obj = temp
|
||||||
meth = "(#{temp} = #{ @variable.source })#{ @variable.last }"
|
meth = "(#{temp} = #{ @variable.source })#{ @variable.last }"
|
||||||
if @isNew
|
if @isNew
|
||||||
utility 'extends'
|
utility 'extends'
|
||||||
"""
|
"""
|
||||||
(function() {
|
#{@first}(function() {
|
||||||
#{@idt(1)}var ctor = function(){};
|
#{@idt(1)}var ctor = function(){};
|
||||||
#{@idt(1)}__extends(ctor, #{meth});
|
#{@idt(1)}__extends(ctor, #{meth});
|
||||||
#{@idt(1)}return #{meth}.apply(new ctor, #{ @compileSplatArguments(o) });
|
#{@idt(1)}return #{meth}.apply(new ctor, #{ @compileSplatArguments(o) });
|
||||||
#{@tab}}).call(this)
|
#{@tab}}).call(this)#{@last}
|
||||||
"""
|
"""
|
||||||
else
|
else
|
||||||
"#{@prefix()}#{meth}.apply(#{obj}, #{ @compileSplatArguments(o) })"
|
"#{@first}#{@prefix()}#{meth}.apply(#{obj}, #{ @compileSplatArguments(o) })#{@last}"
|
||||||
|
|
||||||
#### ExtendsNode
|
#### ExtendsNode
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user