diff --git a/lib/cake.js b/lib/cake.js index 656436f2..19183304 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -55,7 +55,7 @@ if (!(exists)) { throw new Error("Cakefile not found in " + (process.cwd())); } - args = process.argv.slice(2, process.argv.length); + args = __slice(process.argv, 2, process.argv.length, true); CoffeeScript.run(fs.readFileSync('Cakefile'), { source: 'Cakefile' }); diff --git a/lib/command.js b/lib/command.js index 93b495da..3526f971 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,5 +1,11 @@ (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 __slice = 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) + ); + }; // 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 @@ -45,8 +51,8 @@ separator = sources.indexOf('--'); flags = []; if (separator >= 0) { - flags = sources.slice((separator + 1), sources.length); - sources = sources.slice(0, separator); + flags = __slice(sources, (separator + 1), sources.length, true); + sources = __slice(sources, 0, separator, true); } process.ARGV = (process.argv = flags); if (options.watch) { @@ -202,8 +208,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(2, options.arguments.length); - return sources; + return sources = __slice(options.arguments, 2, options.arguments.length, true); }; // The compile-time options to pass to the CoffeeScript compiler. compile_options = function compile_options(source) { diff --git a/lib/nodes.js b/lib/nodes.js index eea00fa7..b568add4 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -430,11 +430,13 @@ // 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, soaked, temp; + var _a, _b, _c, baseline, complete, only, op, part, prop, props, replace, soaked, splice, temp; soaked = false; only = del(o, 'only_first'); op = del(o, 'operation'); - props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties; + splice = del(o, 'splice'); + replace = del(o, 'replace'); + props = only ? __slice(this.properties, 0, this.properties.length - 1, true) : this.properties; baseline = this.base.compile(o); if (this.base instanceof ObjectNode && this.has_properties()) { baseline = "(" + baseline + ")"; @@ -454,7 +456,12 @@ } } else if (prop instanceof SliceNode) { o.array = complete; - part = prop.compile_slice(o); + if (splice) { + o.replace = replace; + part = prop.compile_splice(o); + } else { + part = prop.compile_slice(o); + } baseline = part; complete = part; this.last = part; @@ -720,14 +727,33 @@ }; Coffeescript.extend(SliceNode, BaseNode); SliceNode.prototype.type = 'Slice'; - SliceNode.prototype.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.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) { - throw "'" + this.type + "' cannot compile outside of 'ValueNode'"; + var from, plus_part, to; + from = this.range.from.compile(o); + to = this.range.to.compile(o); + plus_part = this.range.exclusive ? '' : ' + 1'; + return ".slice(" + from + ", " + to + plus_part + ")"; + }; + SliceNode.prototype.compile_splice = function compile_splice(o) { + var _a, _b, _c, 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'); + replace = del(o, 'replace'); + from = (typeof (_b = this.range.from) !== "undefined" && _b !== null) ? this.range.from : literal('null'); + to = (typeof (_c = this.range.to) !== "undefined" && _c !== null) ? this.range.to : literal('null'); + exclusive = this.range.exclusive ? 'true' : 'false'; + ref = new ValueNode(literal('__splice')); + call = new CallNode(ref, [literal(array), from, to, literal(exclusive), replace]); + return call.compile(o); }; SliceNode.prototype.compile_slice = function compile_slice(o) { var _a, _b, _c, array, call, exclusive, from, ref, to; if ((typeof (_a = o.scope) !== "undefined" && _a !== null)) { - o.scope.assign('__slice', this.code, true); + o.scope.assign('__slice', this.slice_code, true); } array = del(o, 'array'); from = (typeof (_b = this.range.from) !== "undefined" && _b !== null) ? this.range.from : literal('null'); @@ -989,17 +1015,18 @@ // Compile the assignment from an array splice literal, using JavaScript's // `Array#splice` method. AssignNode.prototype.compile_splice = function compile_splice(o) { - var from, l, name, plus, range, to, val; - name = this.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))" + return this.variable.compile(merge(o, { + only_first: true, + splice: true, + replace: this.value })); - 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); diff --git a/src/nodes.coffee b/src/nodes.coffee index f9d153a6..91642a14 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -308,6 +308,8 @@ 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,7 +326,11 @@ exports.ValueNode: class ValueNode extends BaseNode complete: complete + @SOAK + (baseline: + prop.compile(o)) else if prop instanceof SliceNode o.array: complete - part: prop.compile_slice(o) + if splice + o.replace: replace + part: prop.compile_splice(o) + else + part: prop.compile_slice(o) baseline = part complete = part @last: part @@ -526,7 +532,7 @@ exports.RangeNode: class RangeNode extends BaseNode exports.SliceNode: class SliceNode extends BaseNode type: 'Slice' - code: ''' + slice_code: ''' function __slice(array, from, to, exclusive) { return array.slice( (from < 0 ? from + array.length : from || 0), @@ -535,15 +541,39 @@ exports.SliceNode: class SliceNode extends BaseNode } ''' + 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) -> @children: [@range: range] this compile_node: (o) -> - throw "'$@type' cannot compile outside of 'ValueNode'" + from: @range.from.compile(o) + to: @range.to.compile(o) + plus_part: if @range.exclusive then '' else ' + 1' + ".slice($from, $to$plus_part)" + + compile_splice: (o) -> + o.scope.assign('__splice', @splice_code, true) if o.scope? + 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' + ref: new ValueNode literal('__splice') + call: new CallNode ref, [literal(array), from, to, literal(exclusive), replace] + call.compile(o) compile_slice: (o) -> - o.scope.assign('__slice', @code, true) if o.scope? + o.scope.assign('__slice', @slice_code, true) if o.scope? array: del o, 'array' from: if @range.from? then @range.from else literal('null') to: if @range.to? then @range.to else literal('null') @@ -742,14 +772,14 @@ exports.AssignNode: class AssignNode extends BaseNode # Compile the assignment from an array splice literal, using JavaScript's # `Array#splice` method. compile_splice: (o) -> - 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))" + # 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))" + @variable.compile(merge(o, {only_first: true, splice: true, replace: @value})) #### CodeNode