Added function call's flexibility with splats to array literals, factoring out splat compiling, and adjusted tests

This commit is contained in:
matehat 2010-03-18 09:27:13 -04:00
parent b72641693d
commit fe04f8ce6b
3 changed files with 108 additions and 72 deletions

View File

@ -419,6 +419,11 @@
exports.CallNode = (function() { exports.CallNode = (function() {
CallNode = function CallNode(variable, args) { CallNode = function CallNode(variable, args) {
this.children = flatten([(this.variable = variable), (this.args = (args || []))]); this.children = flatten([(this.variable = variable), (this.args = (args || []))]);
this.compile_splat_arguments = (function(func, obj, args) {
return (function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));;
});
}(SplatNode.compile_mixed_array, this, [this.args]));
this.prefix = ''; this.prefix = '';
return this; return this;
}; };
@ -473,33 +478,6 @@
} }
return '' + this.prefix + (meth) + ".apply(" + obj + ", " + (this.compile_splat_arguments(o)) + ")"; return '' + this.prefix + (meth) + ".apply(" + obj + ", " + (this.compile_splat_arguments(o)) + ")";
}; };
// Converts arbitrary number of arguments, mixed with splats, to
// a proper array to pass to an `.apply()` call
CallNode.prototype.compile_splat_arguments = function compile_splat_arguments(o) {
var _a, _b, _c, arg, args, code, i, prev;
args = [];
i = 0;
_a = this.args;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
arg = _a[_b];
code = arg.compile(o);
if (!(arg instanceof SplatNode)) {
prev = args[i - 1];
if (i === 1 && prev.substr(0, 1) === '[' && prev.substr(prev.length - 1, 1) === ']') {
args[i - 1] = '' + (prev.substr(0, prev.length - 1)) + ", " + code + "]";
continue;
} else if (i > 1 && prev.substr(0, 9) === '.concat([' && prev.substr(prev.length - 2, 2) === '])') {
args[i - 1] = '' + (prev.substr(0, prev.length - 2)) + ", " + code + "])";
continue;
} else {
code = "[" + code + "]";
}
}
args.push(i === 0 ? code : ".concat(" + code + ")");
i += 1;
}
return args.join('');
};
return CallNode; return CallNode;
}).call(this); }).call(this);
//### CurryNode //### CurryNode
@ -508,6 +486,11 @@
exports.CurryNode = (function() { exports.CurryNode = (function() {
CurryNode = function CurryNode(meth, args) { CurryNode = function CurryNode(meth, args) {
this.children = flatten([(this.meth = meth), (this.context = args[0]), (this.args = (args.slice(1) || []))]); this.children = flatten([(this.meth = meth), (this.context = args[0]), (this.args = (args.slice(1) || []))]);
this.compile_splat_arguments = (function(func, obj, args) {
return (function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));;
});
}(SplatNode.compile_mixed_array, this, [this.args]));
return this; return this;
}; };
__extends(CurryNode, CallNode); __extends(CurryNode, CallNode);
@ -725,30 +708,33 @@
exports.ArrayNode = (function() { exports.ArrayNode = (function() {
ArrayNode = function ArrayNode(objects) { ArrayNode = function ArrayNode(objects) {
this.children = (this.objects = objects || []); this.children = (this.objects = objects || []);
this.compile_splat_literal = (function(func, obj, args) {
return (function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));;
});
}(SplatNode.compile_mixed_array, this, [this.objects]));
return this; return this;
}; };
__extends(ArrayNode, BaseNode); __extends(ArrayNode, BaseNode);
ArrayNode.prototype.type = 'Array'; ArrayNode.prototype.type = 'Array';
ArrayNode.prototype.compile_node = function compile_node(o) { ArrayNode.prototype.compile_node = function compile_node(o) {
var _a, _b, _c, code, ending, i, obj, objects; var _a, _b, code, ending, i, obj, objects;
o.indent = this.idt(1); o.indent = this.idt(1);
objects = (function() { objects = [];
_a = []; _b = this.objects; _a = this.objects;
for (i = 0, _c = _b.length; i < _c; i++) { for (i = 0, _b = _a.length; i < _b; i++) {
obj = _b[i]; obj = _a[i];
_a.push((function() { code = obj.compile(o);
code = obj.compile(o); if (obj instanceof SplatNode) {
if (obj instanceof CommentNode) { return this.compile_splat_literal(this.objects, o);
return "\n" + code + "\n" + o.indent; } else if (obj instanceof CommentNode) {
} else if (i === this.objects.length - 1) { objects.push("\n" + code + "\n" + o.indent);
return code; } else if (i === this.objects.length - 1) {
} else { objects.push(code);
return '' + code + ", "; } else {
} objects.push('' + code + ", ");
}).call(this));
} }
return _a; }
}).call(this);
objects = objects.join(''); objects = objects.join('');
ending = objects.indexOf('\n') >= 0 ? "\n" + this.tab + "]" : ']'; ending = objects.indexOf('\n') >= 0 ? "\n" + this.tab + "]" : ']';
return "[" + objects + ending; return "[" + objects + ending;
@ -1074,6 +1060,33 @@
}; };
return SplatNode; return SplatNode;
}).call(this); }).call(this);
// Utility function that converts arbitrary number of elements, mixed with
// splats, to a proper array
SplatNode.compile_mixed_array = function compile_mixed_array(list, o) {
var _a, _b, _c, arg, args, code, i, prev;
args = [];
i = 0;
_a = list;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
arg = _a[_b];
code = arg.compile(o);
if (!(arg instanceof SplatNode)) {
prev = args[i - 1];
if (i === 1 && prev.substr(0, 1) === '[' && prev.substr(prev.length - 1, 1) === ']') {
args[i - 1] = '' + (prev.substr(0, prev.length - 1)) + ", " + code + "]";
continue;
} else if (i > 1 && prev.substr(0, 9) === '.concat([' && prev.substr(prev.length - 2, 2) === '])') {
args[i - 1] = '' + (prev.substr(0, prev.length - 2)) + ", " + code + "])";
continue;
} else {
code = "[" + code + "]";
}
}
args.push(i === 0 ? code : ".concat(" + code + ")");
i += 1;
}
return args.join('');
};
//### WhileNode //### WhileNode
// A while loop, the only sort of low-level loop exposed by CoffeeScript. From // A while loop, the only sort of low-level loop exposed by CoffeeScript. From
// it, all other loops can be manufactured. Useful in cases where you need more // it, all other loops can be manufactured. Useful in cases where you need more

View File

@ -329,6 +329,7 @@ exports.CallNode: class CallNode extends BaseNode
constructor: (variable, args) -> constructor: (variable, args) ->
@children: flatten [@variable: variable, @args: (args or [])] @children: flatten [@variable: variable, @args: (args or [])]
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
@prefix: '' @prefix: ''
# Tag this invocation as creating a new instance. # Tag this invocation as creating a new instance.
@ -365,27 +366,6 @@ exports.CallNode: class CallNode extends BaseNode
meth: "($temp = ${ @variable.source })${ @variable.last }" meth: "($temp = ${ @variable.source })${ @variable.last }"
"$@prefix${meth}.apply($obj, ${ @compile_splat_arguments(o) })" "$@prefix${meth}.apply($obj, ${ @compile_splat_arguments(o) })"
# Converts arbitrary number of arguments, mixed with splats, to
# a proper array to pass to an `.apply()` call
compile_splat_arguments: (o) ->
args: []
i: 0
for arg in @args
code: arg.compile o
if not (arg instanceof SplatNode)
prev: args[i - 1]
if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
continue
else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
continue
else
code: "[$code]"
args.push(if i is 0 then code else ".concat($code)")
i += 1
args.join('')
#### CurryNode #### CurryNode
@ -398,6 +378,7 @@ exports.CurryNode: class CurryNode extends CallNode
constructor: (meth, args) -> constructor: (meth, args) ->
@children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])] @children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
arguments: (o) -> arguments: (o) ->
for arg in @args for arg in @args
@ -567,17 +548,21 @@ exports.ArrayNode: class ArrayNode extends BaseNode
constructor: (objects) -> constructor: (objects) ->
@children: @objects: objects or [] @children: @objects: objects or []
@compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
compile_node: (o) -> compile_node: (o) ->
o.indent: @idt(1) o.indent: @idt(1)
objects: for obj, i in @objects objects: []
for obj, i in @objects
code: obj.compile(o) code: obj.compile(o)
if obj instanceof CommentNode if obj instanceof SplatNode
"\n$code\n$o.indent" return @compile_splat_literal(@objects, o)
else if obj instanceof CommentNode
objects.push "\n$code\n$o.indent"
else if i is @objects.length - 1 else if i is @objects.length - 1
code objects.push code
else else
"$code, " objects.push "$code, "
objects: objects.join('') objects: objects.join('')
ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']' ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']'
"[$objects$ending" "[$objects$ending"
@ -815,6 +800,27 @@ exports.SplatNode: class SplatNode extends BaseNode
compile_value: (o, name, index) -> compile_value: (o, name, index) ->
"Array.prototype.slice.call($name, $index)" "Array.prototype.slice.call($name, $index)"
# Utility function that converts arbitrary number of elements, mixed with
# splats, to a proper array
SplatNode.compile_mixed_array: (list, o) ->
args: []
i: 0
for arg in list
code: arg.compile o
if not (arg instanceof SplatNode)
prev: args[i - 1]
if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
continue
else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
continue
else
code: "[$code]"
args.push(if i is 0 then code else ".concat($code)")
i += 1
args.join('')
#### WhileNode #### WhileNode
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From # A while loop, the only sort of low-level loop exposed by CoffeeScript. From

View File

@ -58,4 +58,21 @@ obj: {
@accessor(args...) @accessor(args...)
} }
ok obj.getNames() is 'bob jane ted' ok obj.getNames() is 'bob jane ted'
crowd: [
contenders...
"Mighty Mouse"
]
bests: [
"Mighty Mouse"
contenders[0..3]...
]
ok crowd[0] is contenders[0]
ok crowd[10] is "Mighty Mouse"
ok bests[1] is contenders[0]
ok bests[4] is contenders[3]