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() {
CallNode = function CallNode(variable, 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 = '';
return this;
};
@ -473,33 +478,6 @@
}
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;
}).call(this);
//### CurryNode
@ -508,6 +486,11 @@
exports.CurryNode = (function() {
CurryNode = function CurryNode(meth, args) {
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;
};
__extends(CurryNode, CallNode);
@ -725,30 +708,33 @@
exports.ArrayNode = (function() {
ArrayNode = function ArrayNode(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;
};
__extends(ArrayNode, BaseNode);
ArrayNode.prototype.type = 'Array';
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);
objects = (function() {
_a = []; _b = this.objects;
for (i = 0, _c = _b.length; i < _c; i++) {
obj = _b[i];
_a.push((function() {
code = obj.compile(o);
if (obj instanceof CommentNode) {
return "\n" + code + "\n" + o.indent;
} else if (i === this.objects.length - 1) {
return code;
} else {
return '' + code + ", ";
}
}).call(this));
objects = [];
_a = this.objects;
for (i = 0, _b = _a.length; i < _b; i++) {
obj = _a[i];
code = obj.compile(o);
if (obj instanceof SplatNode) {
return this.compile_splat_literal(this.objects, o);
} else if (obj instanceof CommentNode) {
objects.push("\n" + code + "\n" + o.indent);
} else if (i === this.objects.length - 1) {
objects.push(code);
} else {
objects.push('' + code + ", ");
}
return _a;
}).call(this);
}
objects = objects.join('');
ending = objects.indexOf('\n') >= 0 ? "\n" + this.tab + "]" : ']';
return "[" + objects + ending;
@ -1074,6 +1060,33 @@
};
return SplatNode;
}).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
// 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

View File

@ -329,6 +329,7 @@ exports.CallNode: class CallNode extends BaseNode
constructor: (variable, args) ->
@children: flatten [@variable: variable, @args: (args or [])]
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
@prefix: ''
# Tag this invocation as creating a new instance.
@ -365,27 +366,6 @@ exports.CallNode: class CallNode extends BaseNode
meth: "($temp = ${ @variable.source })${ @variable.last }"
"$@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
@ -398,6 +378,7 @@ exports.CurryNode: class CurryNode extends CallNode
constructor: (meth, args) ->
@children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
arguments: (o) ->
for arg in @args
@ -567,17 +548,21 @@ exports.ArrayNode: class ArrayNode extends BaseNode
constructor: (objects) ->
@children: @objects: objects or []
@compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
compile_node: (o) ->
o.indent: @idt(1)
objects: for obj, i in @objects
objects: []
for obj, i in @objects
code: obj.compile(o)
if obj instanceof CommentNode
"\n$code\n$o.indent"
if obj instanceof SplatNode
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
code
objects.push code
else
"$code, "
objects.push "$code, "
objects: objects.join('')
ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']'
"[$objects$ending"
@ -815,6 +800,27 @@ exports.SplatNode: class SplatNode extends BaseNode
compile_value: (o, 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
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From

View File

@ -58,4 +58,21 @@ obj: {
@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]