diff --git a/Rakefile b/Rakefile index 7b40a961..c369091b 100644 --- a/Rakefile +++ b/Rakefile @@ -35,7 +35,7 @@ namespace :build do desc "Rebuild the Underscore.coffee documentation page" task :underscore do - sh "uv -s coffeescript -t idle -h src/underscore.coffee > documentation/underscore.html" + sh "uv -s coffeescript -t idle -h examples/underscore.coffee > documentation/underscore.html" end end diff --git a/src/underscore.coffee b/examples/underscore.coffee similarity index 99% rename from src/underscore.coffee rename to examples/underscore.coffee index e6a2b531..59970014 100644 --- a/src/underscore.coffee +++ b/examples/underscore.coffee @@ -240,7 +240,7 @@ # Trim out all falsy values from an array. - _.compact: (array) -> array[i] for i in [0...array.length] when array[i] + _.compact: (array) -> item for item in array when item # Return a completely flattened version of an array. diff --git a/lib/coffee_script/nodes.js b/lib/coffee_script/nodes.js index 30614679..03b581c8 100644 --- a/lib/coffee_script/nodes.js +++ b/lib/coffee_script/nodes.js @@ -1,13 +1,7 @@ (function(){ - var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ThrowNode, TryNode, ValueNode, WhileNode, _, del, inherit, merge, statement; + var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement; var __hasProp = Object.prototype.hasOwnProperty; - if ((typeof process !== "undefined" && process !== null)) { - process.mixin(require('./scope')); - _ = require('./underscore')._; - } else { - this.exports = this; - _ = this._; - } + (typeof process !== "undefined" && process !== null) ? process.mixin(require('./scope')) : (this.exports = this); // Some helper functions // Tabs are two spaces for pretty printing. TAB = ' '; @@ -16,10 +10,44 @@ IDENTIFIER = /^[a-zA-Z$_](\w|\$)*$/; // Merge objects. merge = function merge(options, overrides) { - return _.tap({}, function(fresh) { - _.extend(fresh, options); - return _.extend(fresh, overrides); - }); + var _a, _b, fresh, key, val; + fresh = {}; + _a = options; + for (key in _a) if (__hasProp.call(_a, key)) { + val = _a[key]; + ((fresh[key] = val)); + } + if (overrides) { + _b = overrides; + for (key in _b) if (__hasProp.call(_b, key)) { + val = _b[key]; + ((fresh[key] = val)); + } + } + return fresh; + }; + // Trim out all falsy values from an array. + compact = function compact(array) { + var _a, _b, _c, item; + _a = []; _b = array; + for (_c = 0; _c < _b.length; _c++) { + item = _b[_c]; + if (item) { + _a.push(item); + } + } + return _a; + }; + // Return a completely flattened version of an array. + flatten = function flatten(array) { + var _a, _b, item, memo; + memo = []; + _a = array; + for (_b = 0; _b < _a.length; _b++) { + item = _a[_b]; + item instanceof Array ? (memo = memo.concat(item)) : memo.push(item); + } + return memo; }; // Delete a key from an object, returning the value. del = function del(obj, key) { @@ -69,7 +97,7 @@ // already been asked to return the result. Node.prototype.compile = function compile(o) { var closure, top; - this.options = _.clone(o || {}); + this.options = merge(o || {}); this.indent = o.indent; top = this.top_sensitive() ? this.options.top : del(this.options, 'top'); closure = this.is_statement() && !this.is_statement_only() && !top && !this.options.returns && !(this instanceof CommentNode) && !this.contains(function(node) { @@ -111,10 +139,16 @@ }; // toString representation of the node, for inspecting the parse tree. Node.prototype.toString = function toString(idt) { + var _a, _b, _c, child; idt = idt || ''; - return '\n' + idt + this.type + _.map(this.children, function(child) { - return child.toString(idt + TAB); - }).join(''); + return '\n' + idt + this.type + ((function() { + _a = []; _b = this.children; + for (_c = 0; _c < _b.length; _c++) { + child = _b[_c]; + _a.push(child.toString(idt + TAB)); + } + return _a; + }).call(this)).join(''); }; // Default implementations of the common node methods. Node.prototype.unwrap = function unwrap() { @@ -134,7 +168,7 @@ Expressions = (exports.Expressions = inherit(Node, { type: 'Expressions', constructor: function constructor(nodes) { - this.children = (this.expressions = _.compact(_.flatten(nodes || []))); + this.children = (this.expressions = compact(flatten(nodes || []))); return this; }, // Tack an expression on to the end of this expression list. @@ -173,7 +207,7 @@ _a = []; _b = this.expressions; for (_c = 0; _c < _b.length; _c++) { node = _b[_c]; - _a.push(this.compile_expression(node, _.clone(o))); + _a.push(this.compile_expression(node, merge(o))); } return _a; }).call(this)).join("\n"); @@ -284,7 +318,7 @@ type: 'Value', SOAK: " == undefined ? undefined : ", constructor: function constructor(base, properties) { - this.children = _.flatten([(this.base = base), (this.properties = (properties || []))]); + this.children = flatten([(this.base = base), (this.properties = (properties || []))]); return this; }, push: function push(prop) { @@ -368,7 +402,7 @@ CallNode = (exports.CallNode = inherit(Node, { type: 'Call', constructor: function constructor(variable, args) { - this.children = _.flatten([(this.variable = variable), (this.args = (args || []))]); + this.children = flatten([(this.variable = variable), (this.args = (args || []))]); this.prefix = ''; return this; }, @@ -384,9 +418,7 @@ // Compile a vanilla function call. compile_node: function compile_node(o) { var _a, _b, _c, arg, args; - if (_.any(this.args, function(a) { - return a instanceof SplatNode; - })) { + if (this.args[this.args.length - 1] instanceof SplatNode) { return this.compile_splat(o); } args = ((function() { @@ -812,12 +844,17 @@ return true; }, toString: function toString(idt) { - var children; + var _a, _b, _c, child, children; idt = idt || ''; - children = _.flatten([this.params, this.body.expressions]); - return '\n' + idt + this.type + _.map(children, function(child) { - return child.toString(idt + TAB); - }).join(''); + children = flatten([this.params, this.body.expressions]); + return '\n' + idt + this.type + ((function() { + _a = []; _b = children; + for (_c = 0; _c < _b.length; _c++) { + child = _b[_c]; + _a.push(child.toString(idt + TAB)); + } + return _a; + }).call(this)).join(''); } })); // A splat, either as a parameter to a function, an argument to a call, @@ -894,7 +931,7 @@ ASSIGNMENT: ['||=', '&&=', '?='], PREFIX_OPERATORS: ['typeof', 'delete'], constructor: function constructor(operator, first, second, flip) { - this.children = _.compact([(this.first = first), (this.second = second)]); + this.children = compact([(this.first = first), (this.second = second)]); this.operator = this.CONVERSIONS[operator] || operator; this.flip = !!flip; return this; @@ -966,7 +1003,7 @@ TryNode = (exports.TryNode = inherit(Node, { type: 'Try', constructor: function constructor(attempt, error, recovery, ensure) { - this.children = _.compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]); + this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]); this.error = error; return this; }, @@ -1055,7 +1092,7 @@ this.name = _a[0]; this.index = _a[1]; } - this.children = _.compact([this.body, this.source, this.filter]); + this.children = compact([this.body, this.source, this.filter]); return this; }, top_sensitive: function top_sensitive() { @@ -1142,7 +1179,7 @@ this.condition = condition; this.body = body && body.unwrap(); this.else_body = else_body && else_body.unwrap(); - this.children = _.compact([this.condition, this.body, this.else_body]); + this.children = compact([this.condition, this.body, this.else_body]); this.tags = tags || {}; if (this.condition instanceof Array) { this.multiple = true; @@ -1200,7 +1237,7 @@ compile_condition: function compile_condition(o) { var _a, _b, _c, cond; return ((function() { - _a = []; _b = _.flatten([this.condition]); + _a = []; _b = flatten([this.condition]); for (_c = 0; _c < _b.length; _c++) { cond = _b[_c]; _a.push(cond.compile(o)); @@ -1216,7 +1253,7 @@ compile_statement: function compile_statement(o) { var body, child, com_dent, cond_o, else_part, if_dent, if_part, prefix; child = del(o, 'chain_child'); - cond_o = _.clone(o); + cond_o = merge(o); del(cond_o, 'returns'); o.indent = this.idt(1); o.top = true; diff --git a/src/nodes.coffee b/src/nodes.coffee index 95a7a5eb..f0fe6510 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1,9 +1,7 @@ if process? process.mixin require './scope' - _: require('./underscore')._ else this.exports: this - _: this._ # Some helper functions @@ -16,9 +14,20 @@ IDENTIFIER: /^[a-zA-Z$_](\w|\$)*$/ # Merge objects. merge: (options, overrides) -> - _.tap {}, (fresh) -> - _.extend fresh, options - _.extend fresh, overrides + fresh: {} + (fresh[key]: val) for key, val of options + (fresh[key]: val) for key, val of overrides if overrides + fresh + +# Trim out all falsy values from an array. +compact: (array) -> item for item in array when item + +# Return a completely flattened version of an array. +flatten: (array) -> + memo: [] + for item in array + if item instanceof Array then memo: memo.concat(item) else memo.push(item) + memo # Delete a key from an object, returning the value. del: (obj, key) -> @@ -52,7 +61,7 @@ Node: exports.Node: -> # the top level of a block (which would be unnecessary), and we haven't # already been asked to return the result. Node::compile: (o) -> - @options: _.clone o or {} + @options: merge o or {} @indent: o.indent top: if @top_sensitive() then @options.top else del @options, 'top' closure: @is_statement() and not @is_statement_only() and not top and @@ -83,7 +92,7 @@ Node::contains: (block) -> # toString representation of the node, for inspecting the parse tree. Node::toString: (idt) -> idt ||= '' - '\n' + idt + @type + _.map(@children, (child) -> child.toString(idt + TAB)).join('') + '\n' + idt + @type + (child.toString(idt + TAB) for child in @children).join('') # Default implementations of the common node methods. Node::unwrap: -> this @@ -97,7 +106,7 @@ Expressions: exports.Expressions: inherit Node, { type: 'Expressions' constructor: (nodes) -> - @children: @expressions: _.compact _.flatten nodes or [] + @children: @expressions: compact flatten nodes or [] this # Tack an expression on to the end of this expression list. @@ -130,7 +139,7 @@ Expressions: exports.Expressions: inherit Node, { # Compile each expression in the Expressions body. compile_node: (o) -> - (@compile_expression(node, _.clone(o)) for node in @expressions).join("\n") + (@compile_expression(node, merge(o)) for node in @expressions).join("\n") # If this is the top-level Expressions, wrap everything in a safety closure. compile_root: (o) -> @@ -222,7 +231,7 @@ ValueNode: exports.ValueNode: inherit Node, { SOAK: " == undefined ? undefined : " constructor: (base, properties) -> - @children: _.flatten [@base: base, @properties: (properties or [])] + @children: flatten [@base: base, @properties: (properties or [])] this push: (prop) -> @@ -303,7 +312,7 @@ CallNode: exports.CallNode: inherit Node, { type: 'Call' constructor: (variable, args) -> - @children: _.flatten [@variable: variable, @args: (args or [])] + @children: flatten [@variable: variable, @args: (args or [])] @prefix: '' this @@ -318,7 +327,7 @@ CallNode: exports.CallNode: inherit Node, { # Compile a vanilla function call. compile_node: (o) -> - return @compile_splat(o) if _.any @args, (a) -> a instanceof SplatNode + return @compile_splat(o) if @args[@args.length - 1] instanceof SplatNode args: (arg.compile(o) for arg in @args).join(', ') return @compile_super(args, o) if @variable is 'super' @prefix + @variable.compile(o) + '(' + args + ')' @@ -660,8 +669,8 @@ CodeNode: exports.CodeNode: inherit Node, { toString: (idt) -> idt ||= '' - children: _.flatten [@params, @body.expressions] - '\n' + idt + @type + _.map(children, (child) -> child.toString(idt + TAB)).join('') + children: flatten [@params, @body.expressions] + '\n' + idt + @type + (child.toString(idt + TAB) for child in children).join('') } @@ -740,7 +749,7 @@ OpNode: exports.OpNode: inherit Node, { PREFIX_OPERATORS: ['typeof', 'delete'] constructor: (operator, first, second, flip) -> - @children: _.compact [@first: first, @second: second] + @children: compact [@first: first, @second: second] @operator: @CONVERSIONS[operator] or operator @flip: !!flip this @@ -788,7 +797,7 @@ TryNode: exports.TryNode: inherit Node, { type: 'Try' constructor: (attempt, error, recovery, ensure) -> - @children: _.compact [@attempt: attempt, @recovery: recovery, @ensure: ensure] + @children: compact [@attempt: attempt, @recovery: recovery, @ensure: ensure] @error: error this @@ -869,7 +878,7 @@ ForNode: exports.ForNode: inherit Node, { @step: source.step @object: !!source.object [@name, @index]: [@index, @name] if @object - @children: _.compact [@body, @source, @filter] + @children: compact [@body, @source, @filter] this top_sensitive: -> @@ -933,7 +942,7 @@ IfNode: exports.IfNode: inherit Node, { @condition: condition @body: body and body.unwrap() @else_body: else_body and else_body.unwrap() - @children: _.compact [@condition, @body, @else_body] + @children: compact [@condition, @body, @else_body] @tags: tags or {} @multiple: true if @condition instanceof Array @condition: new OpNode('!', new ParentheticalNode(@condition)) if @tags.invert @@ -973,7 +982,7 @@ IfNode: exports.IfNode: inherit Node, { @statement ||= !!(@comment or @tags.statement or @body.is_statement() or (@else_body and @else_body.is_statement())) compile_condition: (o) -> - (cond.compile(o) for cond in _.flatten([@condition])).join(' || ') + (cond.compile(o) for cond in flatten([@condition])).join(' || ') compile_node: (o) -> if @is_statement() then @compile_statement(o) else @compile_ternary(o) @@ -982,7 +991,7 @@ IfNode: exports.IfNode: inherit Node, { # force sub-else bodies into statement form. compile_statement: (o) -> child: del o, 'chain_child' - cond_o: _.clone o + cond_o: merge o del cond_o, 'returns' o.indent: @idt(1) o.top: true