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

Merged in StanAngeloff excellent slice branch, applying recent factoring of utility functions

This commit is contained in:
matehat 2010-03-30 15:43:30 -04:00
parent 76ade0cb4d
commit da43c70488
11 changed files with 243 additions and 414 deletions

View file

@ -1,6 +1,15 @@
(function(){ (function(){
var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks; var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks;
var Coffeescript = { var Coffeescript = {
slice: function(array, from, to, exclusive) {
return array.slice.apply(array, Coffeescript.range(array, from, to, exclusive));
},
range: function(array, from, to, exclusive) {
return [
(from < 0 ? from + array.length : from || 0),
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)
];
},
hasProp: Object.prototype.hasOwnProperty hasProp: Object.prototype.hasOwnProperty
}; };
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/) // `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
@ -55,7 +64,7 @@
if (!(exists)) { if (!(exists)) {
throw new Error("Cakefile not found in " + (process.cwd())); throw new Error("Cakefile not found in " + (process.cwd()));
} }
args = __slice(process.argv, 2, process.argv.length, true); args = Coffeescript.slice(process.argv, 2, process.argv.length, true);
CoffeeScript.run(fs.readFileSync('Cakefile'), { CoffeeScript.run(fs.readFileSync('Cakefile'), {
source: 'Cakefile' source: 'Cakefile'
}); });

View file

@ -1,10 +1,15 @@
(function(){ (function(){
var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js; var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js;
var __slice = function __slice(array, from, to, exclusive) { var Coffeescript = {
return array.slice( slice: function(array, from, to, exclusive) {
(from < 0 ? from + array.length : from || 0), return array.slice.apply(array, Coffeescript.range(array, from, to, exclusive));
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1) },
); range: function(array, from, to, exclusive) {
return [
(from < 0 ? from + array.length : from || 0),
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)
];
}
}; };
// The `coffee` utility. Handles command-line compilation of CoffeeScript // The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout, piped to // into various forms: saved into `.js` files or printed to stdout, piped to
@ -51,8 +56,8 @@
separator = sources.indexOf('--'); separator = sources.indexOf('--');
flags = []; flags = [];
if (separator >= 0) { if (separator >= 0) {
flags = __slice(sources, (separator + 1), sources.length, true); flags = Coffeescript.slice(sources, (separator + 1), sources.length, true);
sources = __slice(sources, 0, separator, true); sources = Coffeescript.slice(sources, 0, separator, true);
} }
process.ARGV = (process.argv = flags); process.ARGV = (process.argv = flags);
if (options.watch) { if (options.watch) {
@ -208,7 +213,8 @@
o = (options = option_parser.parse(process.argv)); o = (options = option_parser.parse(process.argv));
options.run = !(o.compile || o.print || o.lint); options.run = !(o.compile || o.print || o.lint);
options.print = !!(o.print || (o.eval || o.stdio && o.compile)); options.print = !!(o.print || (o.eval || o.stdio && o.compile));
return sources = __slice(options.arguments, 2, options.arguments.length, true); sources = Coffeescript.slice(options.arguments, 2, options.arguments.length, true);
return sources;
}; };
// The compile-time options to pass to the CoffeeScript compiler. // The compile-time options to pass to the CoffeeScript compiler.
compile_options = function compile_options(source) { compile_options = function compile_options(source) {

View file

@ -1,5 +1,8 @@
(function(){ (function(){
var ACCESSORS, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts; var ACCESSORS, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts;
var Coffeescript = {
aslice: Array.prototype.slice
};
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt // The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
// matches against the beginning of the source code. When a match is found, // matches against the beginning of the source code. When a match is found,
// a token is produced, we consume the match, and start again. Tokens are in the // a token is produced, we consume the match, and start again. Tokens are in the
@ -236,7 +239,7 @@
// balanced (ie. strings, JS literals). // balanced (ie. strings, JS literals).
Lexer.prototype.balanced_token = function balanced_token() { Lexer.prototype.balanced_token = function balanced_token() {
var delimited; var delimited;
delimited = Array.prototype.slice.call(arguments, 0, arguments.length - 0); delimited = Coffeescript.aslice.call(arguments, 0, arguments.length - 0);
return balanced_string(this.chunk, delimited); return balanced_string(this.chunk, delimited);
}; };
// Matches and conumes comments. We pass through comments into JavaScript, // Matches and conumes comments. We pass through comments into JavaScript,

View file

@ -8,14 +8,24 @@
child.prototype = new ctor(); child.prototype = new ctor();
child.prototype.constructor = child; child.prototype.constructor = child;
}, },
slice: function(array, from, to, exclusive) {
return array.slice.apply(array, Coffeescript.range(array, from, to, exclusive));
},
range: function(array, from, to, exclusive) {
return [
(from < 0 ? from + array.length : from || 0),
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)
];
},
bind: function(func, obj, args) { bind: function(func, obj, args) {
obj = obj || {}; obj = obj || {};
return (typeof args !== "undefined" && args !== null) ? function() { return (typeof args !== 'undefined' && args !== null) ? function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0))); return func.apply(obj, args.concat(Coffeescript.aslice.call(arguments, 0)));
} : function() { } : function() {
return func.apply(obj, arguments); return func.apply(obj, arguments);
}; };
} },
aslice: Array.prototype.slice
}; };
// `nodes.coffee` contains all of the node classes for the syntax tree. Most // `nodes.coffee` contains all of the node classes for the syntax tree. Most
// nodes are created as the result of actions in the [grammar](grammar.html), // nodes are created as the result of actions in the [grammar](grammar.html),
@ -436,7 +446,7 @@
op = del(o, 'operation'); op = del(o, 'operation');
splice = del(o, 'splice'); splice = del(o, 'splice');
replace = del(o, 'replace'); replace = del(o, 'replace');
props = only ? __slice(this.properties, 0, this.properties.length - 1, true) : this.properties; props = only ? Coffeescript.slice(this.properties, 0, this.properties.length - 1, true) : this.properties;
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 + ")";
@ -584,7 +594,6 @@
}; };
Coffeescript.extend(CurryNode, CallNode); Coffeescript.extend(CurryNode, CallNode);
CurryNode.prototype.type = 'Curry'; CurryNode.prototype.type = 'Curry';
CurryNode.prototype.body = 'func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)))';
CurryNode.prototype.arguments = function arguments(o) { CurryNode.prototype.arguments = function arguments(o) {
var _a, _b, _c, arg; var _a, _b, _c, arg;
_b = this.args; _b = this.args;
@ -727,8 +736,6 @@
}; };
Coffeescript.extend(SliceNode, BaseNode); Coffeescript.extend(SliceNode, BaseNode);
SliceNode.prototype.type = 'Slice'; SliceNode.prototype.type = 'Slice';
SliceNode.prototype.slice_code = 'function __slice(array, from, to, exclusive) {\n return array.slice(\n (from < 0 ? from + array.length : from || 0),\n (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)\n );\n }';
SliceNode.prototype.splice_code = 'function __splice(array, from, to, exclusive, replace) {\n var _a;\n return array.splice.apply(\n array,\n [_a = (from < 0 ? from + array.length : from || 0), (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1) - _a].concat(replace)\n );\n }';
SliceNode.prototype.compile_node = function compile_node(o) { SliceNode.prototype.compile_node = function compile_node(o) {
var from, plus_part, to; var from, plus_part, to;
from = this.range.from.compile(o); from = this.range.from.compile(o);
@ -737,29 +744,23 @@
return ".slice(" + from + ", " + to + plus_part + ")"; return ".slice(" + from + ", " + to + plus_part + ")";
}; };
SliceNode.prototype.compile_splice = function compile_splice(o) { SliceNode.prototype.compile_splice = function compile_splice(o) {
var _a, _b, _c, array, call, exclusive, from, ref, replace, to; var _a, _b, array, call, exclusive, from, ref, replace, to;
if ((typeof (_a = o.scope) !== "undefined" && _a !== null)) {
o.scope.assign('__splice', this.splice_code, true);
}
array = del(o, 'array'); array = del(o, 'array');
replace = del(o, 'replace'); replace = del(o, 'replace');
from = (typeof (_b = this.range.from) !== "undefined" && _b !== null) ? this.range.from : literal('null'); from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null');
to = (typeof (_c = this.range.to) !== "undefined" && _c !== null) ? this.range.to : literal('null'); to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false'; exclusive = this.range.exclusive ? 'true' : 'false';
ref = new ValueNode(literal('__splice')); ref = new ValueNode(literal(o.scope.utility('splice')));
call = new CallNode(ref, [literal(array), from, to, literal(exclusive), replace]); call = new CallNode(ref, [literal(array), from, to, literal(exclusive), replace]);
return call.compile(o); return call.compile(o);
}; };
SliceNode.prototype.compile_slice = function compile_slice(o) { SliceNode.prototype.compile_slice = function compile_slice(o) {
var _a, _b, _c, array, call, exclusive, from, ref, to; var _a, _b, array, call, exclusive, from, ref, to;
if ((typeof (_a = o.scope) !== "undefined" && _a !== null)) {
o.scope.assign('__slice', this.slice_code, true);
}
array = del(o, 'array'); array = del(o, 'array');
from = (typeof (_b = this.range.from) !== "undefined" && _b !== null) ? this.range.from : literal('null'); from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null');
to = (typeof (_c = this.range.to) !== "undefined" && _c !== null) ? this.range.to : literal('null'); to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false'; exclusive = this.range.exclusive ? 'true' : 'false';
ref = new ValueNode(literal('__slice')); ref = new ValueNode(literal(o.scope.utility('slice')));
call = new CallNode(ref, [literal(array), from, to, literal(exclusive)]); call = new CallNode(ref, [literal(array), from, to, literal(exclusive)]);
return call.compile(o); return call.compile(o);
}; };
@ -833,7 +834,7 @@
obj = _a[i]; obj = _a[i];
code = obj.compile(o); code = obj.compile(o);
if (obj instanceof SplatNode) { if (obj instanceof SplatNode) {
return this.compile_splat_literal(this.objects, o); return this.compile_splat_literal(o);
} else if (obj instanceof CommentNode) { } else if (obj instanceof CommentNode) {
objects.push("\n" + code + "\n" + o.indent); objects.push("\n" + code + "\n" + o.indent);
} else if (i === this.objects.length - 1) { } else if (i === this.objects.length - 1) {
@ -1162,15 +1163,15 @@
o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]"); o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]");
i += 1; i += 1;
} }
return "" + name + " = Array.prototype.slice.call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")"; return "" + name + " = " + (o.scope.utility('aslice')) + ".call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")";
}; };
// A compiling a splat as a destructuring assignment means slicing arguments // A compiling a splat as a destructuring assignment means slicing arguments
// from the right-hand-side's corresponding array. // from the right-hand-side's corresponding array.
SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) { SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) {
if ((typeof trailings !== "undefined" && trailings !== null)) { if ((typeof trailings !== "undefined" && trailings !== null)) {
return "Array.prototype.slice.call(" + name + ", " + index + ", " + (name) + ".length - " + trailings + ")"; return "" + (o.scope.utility('aslice')) + ".call(" + name + ", " + index + ", " + (name) + ".length - " + trailings + ")";
} else { } else {
return "Array.prototype.slice.call(" + name + ", " + index + ")"; return "" + (o.scope.utility('aslice')) + ".call(" + name + ", " + index + ")";
} }
}; };
// Utility function that converts arbitrary number of elements, mixed with // Utility function that converts arbitrary number of elements, mixed with

File diff suppressed because one or more lines are too long

View file

@ -3,12 +3,13 @@
var Coffeescript = { var Coffeescript = {
bind: function(func, obj, args) { bind: function(func, obj, args) {
obj = obj || {}; obj = obj || {};
return (typeof args !== "undefined" && args !== null) ? function() { return (typeof args !== 'undefined' && args !== null) ? function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0))); return func.apply(obj, args.concat(Coffeescript.aslice.call(arguments, 0)));
} : function() { } : function() {
return func.apply(obj, arguments); return func.apply(obj, arguments);
}; };
}, },
aslice: Array.prototype.slice,
hasProp: Object.prototype.hasOwnProperty hasProp: Object.prototype.hasOwnProperty
}; };
// The CoffeeScript language has a good deal of optional syntax, implicit syntax, // The CoffeeScript language has a good deal of optional syntax, implicit syntax,

View file

@ -97,20 +97,30 @@
// Ensure the CoffeeScript utility object is included in the top level // Ensure the CoffeeScript utility object is included in the top level
// then return a CallNode curried constructor bound to the utility function // then return a CallNode curried constructor bound to the utility function
Scope.prototype.utility = function utility(name) { Scope.prototype.utility = function utility(name) {
var _a, _b, _c, _d, dep;
if (this.parent) { if (this.parent) {
return this.topmost().utility(name); return this.topmost().utility(name);
} }
this.utilities = this.utilities || {}; if ((typeof (_d = utilities.functions[name]) !== "undefined" && _d !== null)) {
this.utilities[name] = true; this.utilities = this.utilities || {};
this.utilities[name] = utilities.functions[name];
_b = (utilities.dependencies[name] || []);
for (_a = 0, _c = _b.length; _a < _c; _a++) {
dep = _b[_a];
this.utility(dep);
}
}
return "" + (utilities.KEY) + "." + name; return "" + (utilities.KEY) + "." + name;
}; };
// Formats an javascript object containing the utility methods required
// in the scope
Scope.prototype.included_utilities = function included_utilities(tab) { Scope.prototype.included_utilities = function included_utilities(tab) {
var _a, _b, _c, _d, key, props; var _a, _b, _c, _d, key, props;
if ((typeof (_d = this.utilities) !== "undefined" && _d !== null)) { if ((typeof (_d = this.utilities) !== "undefined" && _d !== null)) {
props = (function() { props = (function() {
_a = []; _b = this.utilities; _a = []; _b = this.utilities;
for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) {
(typeof (_c = this.utilities[key]) !== "undefined" && _c !== null) ? _a.push(utilities.FORMAT(key, tab)) : null; (typeof (_c = this.utilities[key]) !== "undefined" && _c !== null) ? _a.push(utilities.format(key, tab)) : null;
}} }}
return _a; return _a;
}).call(this); }).call(this);

View file

@ -4,12 +4,23 @@
this.exports = this; this.exports = this;
} }
exports.utilities = (utilities = { exports.utilities = (utilities = {
KEY: "Coffeescript", KEY: "Coffeescript"
FORMAT: function FORMAT(key, tab) {
return "\n " + tab + key + ": " + (utilities[key].replace(/\n/g, "\n" + tab + " ") || 'undefined');
},
extend: 'function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n}',
bind: 'function(func, obj, args) {\n obj = obj || {};\n return (typeof args !== "undefined" && args !== null) ? function() {\n return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));\n } : function() {\n return func.apply(obj, arguments);\n };\n}',
hasProp: "Object.prototype.hasOwnProperty"
}); });
utilities.format = function format(key, tab) {
return "\n " + tab + key + ": " + (utilities.functions[key].replace(/\n/g, "\n" + tab + " ") || 'undefined');
};
utilities.dependencies = {
slice: ['range'],
splice: ['range'],
bind: ['aslice']
};
utilities.functions = {
extend: "function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n}",
bind: "function(func, obj, args) {\n obj = obj || {};\n return (typeof args !== 'undefined' && args !== null) ? function() {\n return func.apply(obj, args.concat(" + (utilities.KEY) + ".aslice.call(arguments, 0)));\n } : function() {\n return func.apply(obj, arguments);\n };\n}",
range: "function(array, from, to, exclusive) {\n return [\n (from < 0 ? from + array.length : from || 0),\n (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)\n ];\n}",
slice: "function(array, from, to, exclusive) {\n return array.slice.apply(array, " + (utilities.KEY) + ".range(array, from, to, exclusive));\n}",
splice: "function(array, from, to, exclusive, replace) {\n var _a, _r = " + (utilities.KEY) + ".range(array, from, to, exclusive);\n return array.splice.apply(array, [_a = _r[0], _r[1] - _a].concat(replace));\n}",
hasProp: "Object.prototype.hasOwnProperty",
aslice: "Array.prototype.slice"
};
})(); })();

View file

@ -420,8 +420,6 @@ exports.CallNode: class CallNode extends BaseNode
exports.CurryNode: class CurryNode extends CallNode exports.CurryNode: class CurryNode extends CallNode
type: 'Curry' type: 'Curry'
body: 'func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)))'
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 @compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
@ -532,25 +530,6 @@ exports.RangeNode: class RangeNode extends BaseNode
exports.SliceNode: class SliceNode extends BaseNode exports.SliceNode: class SliceNode extends BaseNode
type: 'Slice' type: 'Slice'
slice_code: '''
function __slice(array, from, to, exclusive) {
return array.slice(
(from < 0 ? from + array.length : from || 0),
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)
);
}
'''
splice_code: '''
function __splice(array, from, to, exclusive, replace) {
var _a;
return array.splice.apply(
array,
[_a = (from < 0 ? from + array.length : from || 0), (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1) - _a].concat(replace)
);
}
'''
constructor: (range) -> constructor: (range) ->
@children: [@range: range] @children: [@range: range]
this this
@ -562,23 +541,21 @@ exports.SliceNode: class SliceNode extends BaseNode
".slice($from, $to$plus_part)" ".slice($from, $to$plus_part)"
compile_splice: (o) -> compile_splice: (o) ->
o.scope.assign('__splice', @splice_code, true) if o.scope?
array: del o, 'array' array: del o, 'array'
replace: del o, 'replace' replace: del o, 'replace'
from: if @range.from? then @range.from else literal('null') from: if @range.from? then @range.from else literal('null')
to: if @range.to? then @range.to else literal('null') to: if @range.to? then @range.to else literal('null')
exclusive: if @range.exclusive then 'true' else 'false' exclusive: if @range.exclusive then 'true' else 'false'
ref: new ValueNode literal('__splice') ref: new ValueNode literal(o.scope.utility('splice'))
call: new CallNode ref, [literal(array), from, to, literal(exclusive), replace] call: new CallNode ref, [literal(array), from, to, literal(exclusive), replace]
call.compile(o) call.compile(o)
compile_slice: (o) -> compile_slice: (o) ->
o.scope.assign('__slice', @slice_code, true) if o.scope?
array: del o, 'array' array: del o, 'array'
from: if @range.from? then @range.from else literal('null') from: if @range.from? then @range.from else literal('null')
to: if @range.to? then @range.to else literal('null') to: if @range.to? then @range.to else literal('null')
exclusive: if @range.exclusive then 'true' else 'false' exclusive: if @range.exclusive then 'true' else 'false'
ref: new ValueNode literal('__slice') ref: new ValueNode literal(o.scope.utility('slice'))
call: new CallNode ref, [literal(array), from, to, literal(exclusive)] call: new CallNode ref, [literal(array), from, to, literal(exclusive)]
call.compile(o) call.compile(o)
@ -626,7 +603,7 @@ exports.ArrayNode: class ArrayNode extends BaseNode
for obj, i in @objects for obj, i in @objects
code: obj.compile(o) code: obj.compile(o)
if obj instanceof SplatNode if obj instanceof SplatNode
return @compile_splat_literal(@objects, o) return @compile_splat_literal o
else if obj instanceof CommentNode else if obj instanceof CommentNode
objects.push "\n$code\n$o.indent" objects.push "\n$code\n$o.indent"
else if i is @objects.length - 1 else if i is @objects.length - 1
@ -866,13 +843,13 @@ exports.SplatNode: class SplatNode extends BaseNode
for trailing in @trailings for trailing in @trailings
o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]") o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]")
i: + 1 i: + 1
"$name = Array.prototype.slice.call(arguments, $@index, arguments.length - ${@trailings.length})" "$name = ${o.scope.utility('aslice')}.call(arguments, $@index, arguments.length - ${@trailings.length})"
# A compiling a splat as a destructuring assignment means slicing arguments # A compiling a splat as a destructuring assignment means slicing arguments
# from the right-hand-side's corresponding array. # from the right-hand-side's corresponding array.
compile_value: (o, name, index, trailings) -> compile_value: (o, name, index, trailings) ->
if trailings? then "Array.prototype.slice.call($name, $index, ${name}.length - $trailings)" \ if trailings? then "${o.scope.utility('aslice')}.call($name, $index, ${name}.length - $trailings)" \
else "Array.prototype.slice.call($name, $index)" else "${o.scope.utility('aslice')}.call($name, $index)"
# Utility function that converts arbitrary number of elements, mixed with # Utility function that converts arbitrary number of elements, mixed with
# splats, to a proper array # splats, to a proper array

View file

@ -66,17 +66,20 @@ exports.Scope: class Scope
# then return a CallNode curried constructor bound to the utility function # then return a CallNode curried constructor bound to the utility function
utility: (name) -> utility: (name) ->
return @topmost().utility(name) if @parent return @topmost().utility(name) if @parent
@utilities: or {} if utilities.functions[name]?
@utilities[name]: true @utilities: or {}
@utilities[name]: utilities.functions[name]
@utility(dep) for dep in (utilities.dependencies[name] or [])
"${utilities.KEY}.$name" "${utilities.KEY}.$name"
# Formats an javascript object containing the utility methods required
# in the scope
included_utilities: (tab) -> included_utilities: (tab) ->
if @utilities? if @utilities?
props: (utilities.FORMAT(key, tab) for key of @utilities when @utilities[key]?) props: (utilities.format(key, tab) for key of @utilities when @utilities[key]?)
["${utilities.KEY} = {${props.join(', ')}\n$tab}"] ["${utilities.KEY} = {${props.join(', ')}\n$tab}"]
else [] else []
# Does this scope reference any variables that need to be declared in the # Does this scope reference any variables that need to be declared in the
# given function body? # given function body?
has_declarations: (body) -> has_declarations: (body) ->

View file

@ -1,10 +1,17 @@
this.exports: this unless process? this.exports: this unless process?
exports.utilities: utilities: { exports.utilities: utilities: { KEY: "Coffeescript" }
KEY: "Coffeescript"
FORMAT: (key, tab) -> utilities.format: (key, tab) ->
"\n $tab$key: ${utilities[key].replace(/\n/g, "\n$tab ") or 'undefined'}" "\n $tab$key: ${utilities.functions[key].replace(/\n/g, "\n$tab ") or 'undefined'}"
extend: ''' utilities.dependencies: {
slice: ['range']
splice: ['range']
bind: ['aslice']
}
utilities.functions: {
extend: """
function(child, parent) { function(child, parent) {
var ctor = function(){ }; var ctor = function(){ };
ctor.prototype = parent.prototype; ctor.prototype = parent.prototype;
@ -12,16 +19,37 @@ exports.utilities: utilities: {
child.prototype = new ctor(); child.prototype = new ctor();
child.prototype.constructor = child; child.prototype.constructor = child;
} }
''' """
bind: ''' bind: """
function(func, obj, args) { function(func, obj, args) {
obj = obj || {}; obj = obj || {};
return (typeof args !== "undefined" && args !== null) ? function() { return (typeof args !== 'undefined' && args !== null) ? function() {
return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0))); return func.apply(obj, args.concat(${utilities.KEY}.aslice.call(arguments, 0)));
} : function() { } : function() {
return func.apply(obj, arguments); return func.apply(obj, arguments);
}; };
} }
''' """
range: """
function(array, from, to, exclusive) {
return [
(from < 0 ? from + array.length : from || 0),
(to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)
];
}
"""
slice: """
function(array, from, to, exclusive) {
return array.slice.apply(array, ${utilities.KEY}.range(array, from, to, exclusive));
}
"""
splice: """
function(array, from, to, exclusive, replace) {
var _a, _r = ${utilities.KEY}.range(array, from, to, exclusive);
return array.splice.apply(array, [_a = _r[0], _r[1] - _a].concat(replace));
}
"""
hasProp: "Object.prototype.hasOwnProperty" hasProp: "Object.prototype.hasOwnProperty"
aslice: "Array.prototype.slice"
} }