diff --git a/lib/cake.js b/lib/cake.js index 91ec5270..fa509517 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -1,11 +1,6 @@ (function(){ var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks; - var __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; + var __hasProp = Object.prototype.hasOwnProperty; // `cake` is a simplified version of [Make](http://www.gnu.org/software/make/) // ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake)) // for CoffeeScript. You define tasks with names and descriptions in a Cakefile, @@ -58,7 +53,7 @@ if (!(exists)) { throw new Error("Cakefile not found in " + (process.cwd())); } - args = process.argv.slice.apply(process.argv, __range(process.argv, 2, process.argv.length, true)); + args = process.argv.slice(2, process.argv.length); CoffeeScript.run(fs.readFileSync('Cakefile'), { source: 'Cakefile' }); diff --git a/lib/command.js b/lib/command.js index 5967cea7..93b495da 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,11 +1,5 @@ (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 __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 // into various forms: saved into `.js` files or printed to stdout, piped to // [JSLint](http://javascriptlint.com/) or recompiled every time the source is @@ -51,8 +45,8 @@ separator = sources.indexOf('--'); flags = []; if (separator >= 0) { - flags = sources.slice.apply(sources, __range(sources, (separator + 1), sources.length, true)); - sources = sources.slice.apply(sources, __range(sources, 0, separator, true)); + flags = sources.slice((separator + 1), sources.length); + sources = sources.slice(0, separator); } process.ARGV = (process.argv = flags); if (options.watch) { @@ -208,7 +202,7 @@ o = (options = option_parser.parse(process.argv)); options.run = !(o.compile || o.print || o.lint); options.print = !!(o.print || (o.eval || o.stdio && o.compile)); - sources = options.arguments.slice.apply(options.arguments, __range(options.arguments, 2, options.arguments.length, true)); + sources = options.arguments.slice(2, options.arguments.length); return sources; }; // The compile-time options to pass to the CoffeeScript compiler. diff --git a/lib/nodes.js b/lib/nodes.js index a666f7c5..0187b272 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -6,11 +6,6 @@ child.__superClass__ = parent.prototype; child.prototype = new ctor(); child.prototype.constructor = child; - }, __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 = Array.prototype.slice, __bind = function(func, obj, args) { return function() { return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments); @@ -284,7 +279,7 @@ var code; code = this.compile_node(o); if (o.scope.has_assignments(this)) { - code = "" + (this.tab) + "var " + (o.scope.compiled_assignments(this.tab)) + ";\n" + code; + code = "" + (this.tab) + "var " + (o.scope.compiled_assignments()) + ";\n" + code; } if (o.scope.has_declarations(this)) { code = "" + (this.tab) + "var " + (o.scope.compiled_declarations()) + ";\n" + code; @@ -429,13 +424,11 @@ // 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 _a, _b, _c, baseline, complete, only, op, part, prop, props, replace, soaked, splice, temp; + var _a, _b, _c, baseline, complete, only, op, part, prop, props, soaked, temp; soaked = false; only = del(o, 'only_first'); op = del(o, 'operation'); - splice = del(o, 'splice'); - replace = del(o, 'replace'); - props = only ? this.properties.slice.apply(this.properties, __range(this.properties, 0, this.properties.length - 1, true)) : this.properties; + props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties; baseline = this.base.compile(o); if (this.base instanceof ObjectNode && this.has_properties()) { baseline = "(" + baseline + ")"; @@ -453,17 +446,6 @@ } else { complete = complete + this.SOAK + (baseline += prop.compile(o)); } - } else if (prop instanceof SliceNode) { - o.array = complete; - if (splice) { - o.replace = replace; - part = prop.compile_splice(o); - } else { - part = prop.compile_slice(o); - } - baseline = part; - complete = part; - this.last = part; } else { part = prop.compile(o); baseline += part; @@ -733,29 +715,6 @@ plus_part = this.range.exclusive ? '' : ' + 1'; return ".slice(" + from + ", " + to + plus_part + ")"; }; - SliceNode.prototype.compile_splice = function compile_splice(o) { - var _a, _b, args, array, call, exclusive, from, replace, rng, to, v; - array = del(o, 'array'); - replace = del(o, 'replace'); - from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null'); - to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null'); - exclusive = this.range.exclusive ? 'true' : 'false'; - v = o.scope.free_variable(); - rng = new CallNode(new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]); - args = literal("[(" + v + " = " + (rng.compile(o)) + ")[0], " + v + "[1] - " + v + "[0]].concat(" + (replace.compile(o)) + ")"); - call = new CallNode(new ValueNode(literal(array), [literal('.splice.apply')]), [literal(array), args]); - return call.compile(o); - }; - SliceNode.prototype.compile_slice = function compile_slice(o) { - var _a, _b, array, call, exclusive, from, rng, to; - array = del(o, 'array'); - from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null'); - to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null'); - exclusive = this.range.exclusive ? 'true' : 'false'; - rng = new CallNode(new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]); - call = new CallNode(new ValueNode(literal(array), [literal('.slice.apply')]), [literal(array), rng]); - return call.compile(o); - }; return SliceNode; }).call(this); //### ObjectNode @@ -826,7 +785,7 @@ obj = _a[i]; code = obj.compile(o); if (obj instanceof SplatNode) { - return this.compile_splat_literal(o); + 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) { @@ -1008,11 +967,17 @@ // Compile the assignment from an array splice literal, using JavaScript's // `Array#splice` method. AssignNode.prototype.compile_splice = function compile_splice(o) { - return this.variable.compile(merge(o, { - only_first: true, - splice: true, - replace: this.value + var from, l, name, plus, range, to, val; + name = this.variable.compile(merge(o, { + only_first: true })); + l = this.variable.properties.length; + range = this.variable.properties[l - 1].range; + plus = range.exclusive ? '' : ' + 1'; + from = range.from.compile(o); + to = range.to.compile(o) + ' - ' + from + plus; + val = this.value.compile(o); + return "" + (name) + ".splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + val + "))"; }; return AssignNode; }).call(this); @@ -1770,9 +1735,13 @@ // Utility Functions // ----------------- UTILITIES = { + // Correctly set up a prototype chain for inheritance, including a reference + // to the superclass for `super()` calls. See: + // [goog.inherits](http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.source.html#line1206) 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 a function to a calling context, optionally including curried arguments. + // See [Underscore's implementation](http://jashkenas.github.com/coffee-script/documentation/docs/underscore.html#section-47) bind: "function(func, obj, args) {\n return function() {\n return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : 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 }", hasProp: 'Object.prototype.hasOwnProperty', slice: 'Array.prototype.slice' }; diff --git a/lib/scope.js b/lib/scope.js index 76ac5d01..b55ad5eb 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -129,7 +129,7 @@ return this.declared_variables().join(', '); }; // Compile the JavaScript for all of the variable assignments in this scope. - Scope.prototype.compiled_assignments = function compiled_assignments(tab) { + Scope.prototype.compiled_assignments = function compiled_assignments() { return this.assigned_variables().join(', '); }; return Scope; diff --git a/src/nodes.coffee b/src/nodes.coffee index 83e48eaa..d8ca6468 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -188,7 +188,7 @@ exports.Expressions: class Expressions extends BaseNode # declarations of all inner variables pushed up to the top. compile_with_declarations: (o) -> code: @compile_node(o) - code: "${@tab}var ${o.scope.compiled_assignments(@tab)};\n$code" if o.scope.has_assignments(this) + code: "${@tab}var ${o.scope.compiled_assignments()};\n$code" if o.scope.has_assignments(this) code: "${@tab}var ${o.scope.compiled_declarations()};\n$code" if o.scope.has_declarations(this) code @@ -308,8 +308,6 @@ exports.ValueNode: class ValueNode extends BaseNode soaked: false only: del(o, 'only_first') op: del(o, 'operation') - splice: del(o, 'splice') - replace: del(o, 'replace') props: if only then @properties[0...@properties.length - 1] else @properties baseline: @base.compile o baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties() @@ -324,16 +322,6 @@ exports.ValueNode: class ValueNode extends BaseNode complete: "($temp = $complete)$@SOAK" + (baseline: temp + prop.compile(o)) else complete: complete + @SOAK + (baseline: + prop.compile(o)) - else if prop instanceof SliceNode - o.array: complete - if splice - o.replace: replace - part: prop.compile_splice(o) - else - part: prop.compile_slice(o) - baseline = part - complete = part - @last: part else part: prop.compile(o) baseline: + part @@ -542,27 +530,6 @@ exports.SliceNode: class SliceNode extends BaseNode plus_part: if @range.exclusive then '' else ' + 1' ".slice($from, $to$plus_part)" - compile_splice: (o) -> - array: del o, 'array' - replace: del o, 'replace' - from: if @range.from? then @range.from else literal('null') - to: if @range.to? then @range.to else literal('null') - exclusive: if @range.exclusive then 'true' else 'false' - v: o.scope.free_variable() - rng: new CallNode new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)] - args: literal "[($v = ${rng.compile(o)})[0], $v[1] - $v[0]].concat(${replace.compile(o)})" - call: new CallNode new ValueNode(literal(array), [literal('.splice.apply')]), [literal(array), args] - call.compile(o) - - compile_slice: (o) -> - array: del o, 'array' - from: if @range.from? then @range.from else literal('null') - to: if @range.to? then @range.to else literal('null') - exclusive: if @range.exclusive then 'true' else 'false' - rng: new CallNode new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)] - call: new CallNode new ValueNode(literal(array), [literal('.slice.apply')]), [literal(array), rng] - call.compile(o) - #### ObjectNode # An object literal, nothing fancy. @@ -607,7 +574,7 @@ exports.ArrayNode: class ArrayNode extends BaseNode for obj, i in @objects code: obj.compile(o) if obj instanceof SplatNode - return @compile_splat_literal o + 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 @@ -753,7 +720,14 @@ exports.AssignNode: class AssignNode extends BaseNode # Compile the assignment from an array splice literal, using JavaScript's # `Array#splice` method. compile_splice: (o) -> - @variable.compile(merge(o, {only_first: true, splice: true, replace: @value})) + name: @variable.compile merge o, {only_first: true} + l: @variable.properties.length + range: @variable.properties[l - 1].range + plus: if range.exclusive then '' else ' + 1' + from: range.from.compile(o) + to: range.to.compile(o) + ' - ' + from + plus + val: @value.compile(o) + "${name}.splice.apply($name, [$from, $to].concat($val))" #### CodeNode @@ -1328,6 +1302,9 @@ ClosureNode: exports.ClosureNode: { UTILITIES: { + # Correctly set up a prototype chain for inheritance, including a reference + # to the superclass for `super()` calls. See: + # [goog.inherits](http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.source.html#line1206) extend: """ function(child, parent) { var ctor = function(){ }; @@ -1338,22 +1315,15 @@ UTILITIES: { } """ - bind: """ - function(func, obj, args) { - return function() { - return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : 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) - ]; - } - """ + # Bind a function to a calling context, optionally including curried arguments. + # See [Underscore's implementation](http://jashkenas.github.com/coffee-script/documentation/docs/underscore.html#section-47) + bind: """ + function(func, obj, args) { + return function() { + return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments); + }; + } + """ hasProp: 'Object.prototype.hasOwnProperty' diff --git a/src/scope.coffee b/src/scope.coffee index 36cc61d9..42a3abfb 100644 --- a/src/scope.coffee +++ b/src/scope.coffee @@ -87,5 +87,5 @@ exports.Scope: class Scope @declared_variables().join ', ' # Compile the JavaScript for all of the variable assignments in this scope. - compiled_assignments: (tab) -> + compiled_assignments: -> @assigned_variables().join ', ' diff --git a/test/test_ranges_and_slices.coffee b/test/test_ranges_and_slices.coffee index b5cd4062..bae38f05 100644 --- a/test/test_ranges_and_slices.coffee +++ b/test/test_ranges_and_slices.coffee @@ -18,41 +18,11 @@ ok array.join(' ') is "6 7 8 9 10" hello: "Hello World" -ok hello[...] is "Hello World" -ok hello[1..] is "ello World" -ok hello[6..] is "World" -ok hello[6..-1] is "World" -ok hello[6...-1] is "Worl" ok hello[1...1] is "" ok hello[1..1] is "e" ok hello[1...5] is "ello" ok hello[0..4] is "Hello" -ok hello[...-1] is "Hello Worl" -ok hello[...-6] is "Hello" -ok hello[..1000] is "Hello World" - -# http://wiki.ecmascript.org/doku.php?id=proposals:slice_syntax -s: "hello, world" -ok s[3...5] is 'lo' -ok s[10..] is 'ld' a: [0, 1, 2, 3, 4, 5, 6, 7] deepEqual a[2...6], [2, 3, 4, 5] -deepEqual a[-6...-2], [2, 3, 4, 5] -deepEqual a[...2], [0, 1] -# http://techearth.net/python/index.php5?title=Python:Basics:Slices -alphabet: 'abcdefghij' -ok alphabet[1...3] is 'bc' -ok alphabet[...3] is 'abc' -ok alphabet[1..] is 'bcdefghij' -ok alphabet[...] is 'abcdefghij' -ok alphabet[-1..] is 'j' -ok alphabet[...-1] is 'abcdefghi' - -lstFruit: ['apple', 'banana', 'cherry', 'date'] -deepEqual lstFruit[1...3], ['banana', 'cherry'] -lstFruit2: lstFruit[...] -deepEqual lstFruit2, lstFruit -lstFruit[1]: 'blueberry' -deepEqual lstFruit2, ['apple', 'banana', 'cherry', 'date']