From 2d1abd099d9af53806fdcbccd300e391d82a0d2c Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 25 Apr 2010 22:29:43 -0400 Subject: [PATCH] rewriting the Lexer, CommandLine, Nodes, and Rewriter to take advantage of the new DRY object pattern matching. --- Cakefile | 8 +- lib/command.js | 2 +- lib/lexer.js | 61 ++++----- lib/nodes.js | 313 ++++++++++++++++++++++---------------------- lib/rewriter.js | 101 +++++++------- src/command.coffee | 12 +- src/lexer.coffee | 6 +- src/nodes.coffee | 5 +- src/rewriter.coffee | 2 +- 9 files changed, 253 insertions(+), 257 deletions(-) diff --git a/Cakefile b/Cakefile index 65e3240c..a16a3cfe 100644 --- a/Cakefile +++ b/Cakefile @@ -1,7 +1,7 @@ -fs: require 'fs' -helpers: require('./lib/helpers').helpers -CoffeeScript: require './lib/coffee-script' -{spawn: spawn, exec: exec}: require('child_process') +fs: require 'fs' +helpers: require('./lib/helpers').helpers +CoffeeScript: require './lib/coffee-script' +{spawn, exec}: require('child_process') # Run a CoffeeScript through our node/coffee interpreter. run: (args) -> diff --git a/lib/command.js b/lib/command.js index 857f9f93..3f002f2a 100644 --- a/lib/command.js +++ b/lib/command.js @@ -173,7 +173,7 @@ lint = function lint(js) { var jsl, print_it; print_it = function print_it(buffer) { - return puts(buffer.toString()); + return print(buffer.toString()); }; jsl = spawn('jsl', ['-nologo', '-stdin']); jsl.stdout.addListener('data', print_it); diff --git a/lib/lexer.js b/lib/lexer.js index 52e5134c..14ab39af 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -1,5 +1,5 @@ (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, _a, balanced_string, compact, count, helpers, include, starts; var __slice = Array.prototype.slice; // 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, @@ -17,11 +17,12 @@ helpers = this.helpers; } // Import the helpers we need. - include = helpers.include; - count = helpers.count; - starts = helpers.starts; - compact = helpers.compact; - balanced_string = helpers.balanced_string; + _a = helpers; + include = _a.include; + count = _a.count; + starts = _a.starts; + compact = _a.compact; + balanced_string = _a.balanced_string; // The Lexer Class // --------------- // The Lexer class reads a stream of CoffeeScript and divvys it up into tagged @@ -106,10 +107,10 @@ // Language extensions get the highest priority, first chance to tag tokens // as something else. Lexer.prototype.extension_token = function extension_token() { - var _a, _b, _c, extension; - _b = Lexer.extensions; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - extension = _b[_a]; + var _b, _c, _d, extension; + _c = Lexer.extensions; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + extension = _c[_b]; if (extension.call(this)) { return true; } @@ -419,7 +420,7 @@ // definitions versus argument lists in function calls. Walk backwards, tagging // parameters specially in order to make things easier for the parser. Lexer.prototype.tag_parameters = function tag_parameters() { - var _a, i, tok; + var _b, i, tok; if (this.tag() !== ')') { return null; } @@ -430,11 +431,11 @@ if (!tok) { return null; } - if ((_a = tok[0]) === 'IDENTIFIER') { + if ((_b = tok[0]) === 'IDENTIFIER') { tok[0] = 'PARAM'; - } else if (_a === ')') { + } else if (_b === ')') { tok[0] = 'PARAM_END'; - } else if (_a === '(' || _a === 'CALL_START') { + } else if (_b === '(' || _b === 'CALL_START') { tok[0] = 'PARAM_START'; return tok[0]; } @@ -464,23 +465,23 @@ // new Lexer, tokenize the interpolated contents, and merge them into the // token stream. Lexer.prototype.interpolate_string = function interpolate_string(str, escape_quotes) { - var _a, _b, _c, _d, _e, _f, _g, escaped, expr, group, i, idx, inner, interp, interpolated, lexer, match, nested, pi, quote, tag, tok, token, tokens, value; + var _b, _c, _d, _e, _f, _g, _h, escaped, expr, group, i, idx, inner, interp, interpolated, lexer, match, nested, pi, quote, tag, tok, token, tokens, value; if (str.length < 3 || !starts(str, '"')) { return this.token('STRING', str); } else { lexer = new Lexer(); tokens = []; quote = str.substring(0, 1); - _a = [1, 1]; - i = _a[0]; - pi = _a[1]; + _b = [1, 1]; + i = _b[0]; + pi = _b[1]; while (i < str.length - 1) { if (starts(str, '\\', i)) { i += 1; } else if ((match = str.substring(i).match(INTERPOLATION))) { - _b = match; - group = _b[0]; - interp = _b[1]; + _c = match; + group = _c[0]; + interp = _c[1]; if (starts(interp, '@')) { interp = ("this." + (interp.substring(1))); } @@ -499,9 +500,9 @@ nested = lexer.tokenize(("(" + inner + ")"), { line: this.line }); - _c = nested; - for (idx = 0, _d = _c.length; idx < _d; idx++) { - tok = _c[idx]; + _d = nested; + for (idx = 0, _e = _d.length; idx < _e; idx++) { + tok = _d[idx]; tok[0] === 'CALL_END' ? (tok[0] = ')') : null; } nested.pop(); @@ -524,12 +525,12 @@ if (interpolated) { this.token('(', '('); } - _e = tokens; - for (i = 0, _f = _e.length; i < _f; i++) { - token = _e[i]; - _g = token; - tag = _g[0]; - value = _g[1]; + _f = tokens; + for (i = 0, _g = _f.length; i < _g; i++) { + token = _f[i]; + _h = token; + tag = _h[0]; + value = _h[1]; if (tag === 'TOKENS') { this.tokens = this.tokens.concat(value); } else if (tag === 'STRING' && escape_quotes) { diff --git a/lib/nodes.js b/lib/nodes.js index 3ec7df96..232acb50 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1,5 +1,5 @@ (function(){ - var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, compact, del, flatten, helpers, literal, merge, statement, utility; + var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, flatten, helpers, literal, merge, statement, utility; var __extends = function(child, parent) { var ctor = function(){ }; ctor.prototype = parent.prototype; @@ -26,10 +26,11 @@ Scope = this.Scope; } // Import the helpers we plan to use. - compact = helpers.compact; - flatten = helpers.flatten; - merge = helpers.merge; - del = helpers.del; + _a = helpers; + compact = _a.compact; + flatten = _a.flatten; + merge = _a.merge; + del = _a.del; // Helper function that marks a node as a JavaScript *statement*, or as a // *pure_statement*. Statements must be wrapped in a closure when used as an // expression, and nodes tagged as *pure_statement* cannot be closure-wrapped @@ -118,10 +119,10 @@ // and returning true when the block finds a match. `contains` does not cross // scope boundaries. BaseNode.prototype.contains = function contains(block) { - var _a, _b, _c, node; - _b = this.children; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - node = _b[_a]; + var _b, _c, _d, node; + _c = this.children; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + node = _c[_b]; if (block(node)) { return true; } @@ -146,31 +147,31 @@ }; // Perform an in-order traversal of the AST. Crosses scope boundaries. BaseNode.prototype.traverse = function traverse(block) { - var _a, _b, _c, _d, node; - _a = []; _c = this.children; - for (_b = 0, _d = _c.length; _b < _d; _b++) { - node = _c[_b]; - _a.push((function() { + var _b, _c, _d, _e, node; + _b = []; _d = this.children; + for (_c = 0, _e = _d.length; _c < _e; _c++) { + node = _d[_c]; + _b.push((function() { block(node); if (node.traverse) { return node.traverse(block); } })()); } - return _a; + return _b; }; // `toString` representation of the node, for inspecting the parse tree. // This is what `coffee --nodes` prints out. BaseNode.prototype.toString = function toString(idt) { - var _a, _b, _c, _d, child; + var _b, _c, _d, _e, child; idt = idt || ''; return '\n' + idt + this.constructor.name + (function() { - _a = []; _c = this.children; - for (_b = 0, _d = _c.length; _b < _d; _b++) { - child = _c[_b]; - _a.push(child.toString(idt + TAB)); + _b = []; _d = this.children; + for (_c = 0, _e = _d.length; _c < _e; _c++) { + child = _d[_c]; + _b.push(child.toString(idt + TAB)); } - return _a; + return _b; }).call(this).join(''); }; // Default implementations of the common node identification methods. Nodes @@ -254,14 +255,14 @@ } }; Expressions.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, _d, node; + var _b, _c, _d, _e, node; return (function() { - _a = []; _c = this.expressions; - for (_b = 0, _d = _c.length; _b < _d; _b++) { - node = _c[_b]; - _a.push(this.compile_expression(node, merge(o))); + _b = []; _d = this.expressions; + for (_c = 0, _e = _d.length; _c < _e; _c++) { + node = _d[_c]; + _b.push(this.compile_expression(node, merge(o))); } - return _a; + return _b; }).call(this).join("\n"); }; // If we happen to be the top-level **Expressions**, wrap everything in @@ -426,7 +427,7 @@ // 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 _b, _c, _d, baseline, complete, only, op, part, prop, props, soaked, temp; soaked = false; only = del(o, 'only_first'); op = del(o, 'operation'); @@ -436,9 +437,9 @@ baseline = ("(" + baseline + ")"); } complete = (this.last = baseline); - _b = props; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - prop = _b[_a]; + _c = props; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + prop = _c[_b]; this.source = baseline; if (prop.soak_node) { soaked = true; @@ -516,21 +517,21 @@ }; // Compile a vanilla function call. CallNode.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, _d, _e, _f, _g, arg, args; - _b = this.args; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - arg = _b[_a]; + var _b, _c, _d, _e, _f, _g, _h, arg, args; + _c = this.args; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + arg = _c[_b]; if (arg instanceof SplatNode) { return this.compile_splat(o); } } args = (function() { - _d = []; _f = this.args; - for (_e = 0, _g = _f.length; _e < _g; _e++) { - arg = _f[_e]; - _d.push(arg.compile(o)); + _e = []; _g = this.args; + for (_f = 0, _h = _g.length; _f < _h; _f++) { + arg = _g[_f]; + _e.push(arg.compile(o)); } - return _d; + return _e; }).call(this).join(', '); if (this.is_super) { return this.compile_super(args, o); @@ -569,10 +570,10 @@ }; __extends(CurryNode, CallNode); CurryNode.prototype.arguments = function arguments(o) { - var _a, _b, _c, arg; - _b = this.args; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - arg = _b[_a]; + var _b, _c, _d, arg; + _c = this.args; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + arg = _c[_b]; if (arg instanceof SplatNode) { return this.compile_splat_arguments(o); } @@ -653,14 +654,14 @@ __extends(RangeNode, BaseNode); // Compiles the range's source variables -- where it starts and where it ends. RangeNode.prototype.compile_variables = function compile_variables(o) { - var _a, _b, from, to; + var _b, _c, from, to; this.tab = o.indent; - _a = [o.scope.free_variable(), o.scope.free_variable()]; - this.from_var = _a[0]; - this.to_var = _a[1]; - _b = [this.from.compile(o), this.to.compile(o)]; - from = _b[0]; - to = _b[1]; + _b = [o.scope.free_variable(), o.scope.free_variable()]; + this.from_var = _b[0]; + this.to_var = _b[1]; + _c = [this.from.compile(o), this.to.compile(o)]; + from = _c[0]; + to = _c[1]; return "" + this.from_var + " = " + from + "; " + this.to_var + " = " + to + ";\n" + this.tab; }; // When compiled normally, the range returns the contents of the *for loop* @@ -727,22 +728,22 @@ // AssignNodes get interleaved correctly, with no trailing commas or // commas affixed to comments. ObjectNode.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, _d, _e, _f, _g, i, indent, inner, join, last_noncom, non_comments, prop, props; + var _b, _c, _d, _e, _f, _g, _h, i, indent, inner, join, last_noncom, non_comments, prop, props; o.indent = this.idt(1); non_comments = (function() { - _a = []; _c = this.properties; - for (_b = 0, _d = _c.length; _b < _d; _b++) { - prop = _c[_b]; - !(prop instanceof CommentNode) ? _a.push(prop) : null; + _b = []; _d = this.properties; + for (_c = 0, _e = _d.length; _c < _e; _c++) { + prop = _d[_c]; + !(prop instanceof CommentNode) ? _b.push(prop) : null; } - return _a; + return _b; }).call(this); last_noncom = non_comments[non_comments.length - 1]; props = (function() { - _e = []; _f = this.properties; - for (i = 0, _g = _f.length; i < _g; i++) { - prop = _f[i]; - _e.push((function() { + _f = []; _g = this.properties; + for (i = 0, _h = _g.length; i < _h; i++) { + prop = _g[i]; + _f.push((function() { join = ",\n"; if ((prop === last_noncom) || (prop instanceof CommentNode)) { join = "\n"; @@ -754,7 +755,7 @@ return indent + prop.compile(o) + join; }).call(this)); } - return _e; + return _f; }).call(this); props = props.join(''); inner = props ? '\n' + props + '\n' + this.idt() : ''; @@ -772,12 +773,12 @@ }; __extends(ArrayNode, BaseNode); ArrayNode.prototype.compile_node = function compile_node(o) { - var _a, _b, code, ending, i, obj, objects; + var _b, _c, code, ending, i, obj, objects; o.indent = this.idt(1); objects = []; - _a = this.objects; - for (i = 0, _b = _a.length; i < _b; i++) { - obj = _a[i]; + _b = this.objects; + for (i = 0, _c = _b.length; i < _c; i++) { + obj = _b[i]; code = obj.compile(o); if (obj instanceof SplatNode) { return this.compile_splat_literal(this.objects, o); @@ -814,17 +815,17 @@ // equivalent syntax tree and compile that, in pieces. You can see the // constructor, property assignments, and inheritance getting built out below. ClassNode.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, _d, access, applied, construct, extension, func, prop, props, pvar, returns, val; + var _b, _c, _d, _e, access, applied, construct, extension, func, prop, props, pvar, returns, val; extension = this.parent && new ExtendsNode(this.variable, this.parent); constructor = null; props = new Expressions(); o.top = true; - _b = this.properties; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - prop = _b[_a]; - _d = [prop.variable, prop.value]; - pvar = _d[0]; - func = _d[1]; + _c = this.properties; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + prop = _c[_b]; + _e = [prop.variable, prop.value]; + pvar = _e[0]; + func = _e[1]; if (pvar && pvar.base.value === 'constructor' && func instanceof CodeNode) { func.body.push(new ReturnNode(literal('this'))); constructor = new AssignNode(this.variable, func); @@ -927,24 +928,24 @@ // See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring) // for details. AssignNode.prototype.compile_pattern_match = function compile_pattern_match(o) { - var _a, _b, _c, access_class, assigns, code, i, idx, is_string, obj, oindex, olength, splat, val, val_var, value; + var _b, _c, _d, access_class, assigns, code, i, idx, is_string, obj, oindex, olength, splat, val, val_var, value; val_var = o.scope.free_variable(); value = this.value.is_statement() ? ClosureNode.wrap(this.value) : this.value; assigns = [("" + this.tab + val_var + " = " + (value.compile(o)) + ";")]; o.top = true; o.as_statement = true; splat = false; - _a = this.variable.base.objects; - for (i = 0, _b = _a.length; i < _b; i++) { - obj = _a[i]; + _b = this.variable.base.objects; + for (i = 0, _c = _b.length; i < _c; i++) { + obj = _b[i]; // A regular array pattern-match. idx = i; if (this.variable.is_object()) { if (obj instanceof AssignNode) { // A regular object pattern-match. - _c = [obj.value, obj.variable.base]; - obj = _c[0]; - idx = _c[1]; + _d = [obj.value, obj.variable.base]; + obj = _d[0]; + idx = _d[1]; } else { // A shorthand `{a, b, c}: val` pattern-match. idx = obj; @@ -1004,7 +1005,7 @@ // arrow, generates a wrapper that saves the current value of `this` through // a closure. CodeNode.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, code, func, i, name_part, param, params, ref, shared_scope, splat, top; + var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, code, func, i, name_part, param, params, ref, shared_scope, splat, top; shared_scope = del(o, 'shared_scope'); top = del(o, 'top'); o.scope = shared_scope || new Scope(o.scope, this.body, this); @@ -1015,9 +1016,9 @@ i = 0; splat = undefined; params = []; - _b = this.params; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - param = _b[_a]; + _c = this.params; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + param = _c[_b]; if (param instanceof SplatNode && !(typeof splat !== "undefined" && splat !== null)) { splat = param; splat.index = i; @@ -1031,17 +1032,17 @@ i += 1; } params = (function() { - _d = []; _f = params; - for (_e = 0, _g = _f.length; _e < _g; _e++) { - param = _f[_e]; - _d.push(param.compile(o)); + _e = []; _g = params; + for (_f = 0, _h = _g.length; _f < _h; _f++) { + param = _g[_f]; + _e.push(param.compile(o)); } - return _d; + return _e; })(); this.body.make_return(); - _i = params; - for (_h = 0, _j = _i.length; _h < _j; _h++) { - param = _i[_h]; + _j = params; + for (_i = 0, _k = _j.length; _i < _k; _i++) { + param = _j[_i]; (o.scope.parameter(param)); } code = this.body.expressions.length ? ("\n" + (this.body.compile_with_declarations(o)) + "\n") : ''; @@ -1067,25 +1068,25 @@ }; // Custom `traverse` implementation that uses the `real_children`. CodeNode.prototype.traverse = function traverse(block) { - var _a, _b, _c, _d, child; + var _b, _c, _d, _e, child; block(this); - _a = []; _c = this.real_children(); - for (_b = 0, _d = _c.length; _b < _d; _b++) { - child = _c[_b]; - _a.push(child.traverse(block)); + _b = []; _d = this.real_children(); + for (_c = 0, _e = _d.length; _c < _e; _c++) { + child = _d[_c]; + _b.push(child.traverse(block)); } - return _a; + return _b; }; CodeNode.prototype.toString = function toString(idt) { - var _a, _b, _c, _d, child, children; + var _b, _c, _d, _e, child, children; idt = idt || ''; children = (function() { - _a = []; _c = this.real_children(); - for (_b = 0, _d = _c.length; _b < _d; _b++) { - child = _c[_b]; - _a.push(child.toString(idt + TAB)); + _b = []; _d = this.real_children(); + for (_c = 0, _e = _d.length; _c < _e; _c++) { + child = _d[_c]; + _b.push(child.toString(idt + TAB)); } - return _a; + return _b; }).call(this).join(''); return "\n" + idt + children; }; @@ -1104,8 +1105,8 @@ }; __extends(SplatNode, BaseNode); SplatNode.prototype.compile_node = function compile_node(o) { - var _a; - if ((typeof (_a = this.index) !== "undefined" && _a !== null)) { + var _b; + if ((typeof (_b = this.index) !== "undefined" && _b !== null)) { return this.compile_param(o); } else { return this.name.compile(o); @@ -1114,13 +1115,13 @@ // Compiling a parameter splat means recovering the parameters that succeed // the splat in the parameter list, by slicing the arguments object. SplatNode.prototype.compile_param = function compile_param(o) { - var _a, _b, _c, i, name, trailing; + var _b, _c, _d, i, name, trailing; name = this.name.compile(o); o.scope.find(name); i = 0; - _b = this.trailings; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - trailing = _b[_a]; + _c = this.trailings; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + trailing = _c[_b]; o.scope.assign(trailing.compile(o), ("arguments[arguments.length - " + this.trailings.length + " + " + i + "]")); i += 1; } @@ -1136,12 +1137,12 @@ // 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; + var _b, _c, _d, arg, args, code, i, prev; args = []; i = 0; - _b = list; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - arg = _b[_a]; + _c = list; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + arg = _c[_b]; code = arg.compile(o); if (!(arg instanceof SplatNode)) { prev = args[i - 1]; @@ -1267,27 +1268,27 @@ // bin/coffee -e "puts 50 < 65 > 10" // true OpNode.prototype.compile_chain = function compile_chain(o) { - var _a, _b, first, second, shared; + var _b, _c, first, second, shared; shared = this.first.unwrap().second; if (shared.contains_type(CallNode)) { - _a = shared.compile_reference(o); - this.first.second = _a[0]; - shared = _a[1]; + _b = shared.compile_reference(o); + this.first.second = _b[0]; + shared = _b[1]; } - _b = [this.first.compile(o), this.second.compile(o), shared.compile(o)]; - first = _b[0]; - second = _b[1]; - shared = _b[2]; + _c = [this.first.compile(o), this.second.compile(o), shared.compile(o)]; + first = _c[0]; + second = _c[1]; + shared = _c[2]; return "(" + first + ") && (" + shared + " " + this.operator + " " + second + ")"; }; // When compiling a conditional assignment, take care to ensure that the // operands are only evaluated once, even though we have to reference them // more than once. OpNode.prototype.compile_assignment = function compile_assignment(o) { - var _a, first, second; - _a = [this.first.compile(o), this.second.compile(o)]; - first = _a[0]; - second = _a[1]; + var _b, first, second; + _b = [this.first.compile(o), this.second.compile(o)]; + first = _b[0]; + second = _b[1]; if (first.match(IDENTIFIER)) { o.scope.find(first); } @@ -1299,10 +1300,10 @@ // If this is an existence operator, we delegate to `ExistenceNode.compile_test` // to give us the safe references for the variables. OpNode.prototype.compile_existence = function compile_existence(o) { - var _a, first, second, test; - _a = [this.first.compile(o), this.second.compile(o)]; - first = _a[0]; - second = _a[1]; + var _b, first, second, test; + _b = [this.first.compile(o), this.second.compile(o)]; + first = _b[0]; + second = _b[1]; test = ExistenceNode.compile_test(o, this.first); return "" + test + " ? " + first + " : " + second; }; @@ -1387,18 +1388,18 @@ // because other nodes like to check the existence of their variables as well. // Be careful not to double-evaluate anything. ExistenceNode.compile_test = function compile_test(o, variable) { - var _a, _b, _c, first, second; - _a = [variable, variable]; - first = _a[0]; - second = _a[1]; + var _b, _c, _d, first, second; + _b = [variable, variable]; + first = _b[0]; + second = _b[1]; if (variable instanceof CallNode || (variable instanceof ValueNode && variable.has_properties())) { - _b = variable.compile_reference(o); - first = _b[0]; - second = _b[1]; + _c = variable.compile_reference(o); + first = _c[0]; + second = _c[1]; } - _c = [first.compile(o), second.compile(o)]; - first = _c[0]; - second = _c[1]; + _d = [first.compile(o), second.compile(o)]; + first = _d[0]; + second = _d[1]; return "(typeof " + first + " !== \"undefined\" && " + second + " !== null)"; }; return ExistenceNode; @@ -1447,7 +1448,7 @@ // you can map and filter in a single pass. exports.ForNode = (function() { ForNode = function ForNode(body, source, name, index) { - var _a; + var _b; this.body = body; this.name = name; this.index = index || null; @@ -1456,9 +1457,9 @@ this.step = source.step; this.object = !!source.object; if (this.object) { - _a = [this.index, this.name]; - this.name = _a[0]; - this.index = _a[1]; + _b = [this.index, this.name]; + this.name = _b[0]; + this.index = _b[1]; } this.children = compact([this.body, this.source, this.filter]); this.returns = false; @@ -1589,7 +1590,7 @@ // Rewrite a chain of **IfNodes** with their switch condition for equality. // Ensure that the switch expression isn't evaluated more than once. IfNode.prototype.rewrite_switch = function rewrite_switch(o) { - var _a, _b, _c, assigner, cond, i, variable; + var _b, _c, _d, assigner, cond, i, variable; assigner = this.switcher; if (!(this.switcher.unwrap() instanceof LiteralNode)) { variable = literal(o.scope.free_variable()); @@ -1598,12 +1599,12 @@ } this.condition = (function() { if (this.multiple) { - _a = []; _b = this.condition; - for (i = 0, _c = _b.length; i < _c; i++) { - cond = _b[i]; - _a.push(new OpNode('==', (i === 0 ? assigner : this.switcher), cond)); + _b = []; _c = this.condition; + for (i = 0, _d = _c.length; i < _d; i++) { + cond = _c[i]; + _b.push(new OpNode('==', (i === 0 ? assigner : this.switcher), cond)); } - return _a; + return _b; } else { return new OpNode('==', assigner, this.condition); } @@ -1635,14 +1636,14 @@ return this.statement = this.statement || !!(this.comment || this.tags.statement || this.body.is_statement() || (this.else_body && this.else_body.is_statement())); }; IfNode.prototype.compile_condition = function compile_condition(o) { - var _a, _b, _c, _d, cond; + var _b, _c, _d, _e, cond; return (function() { - _a = []; _c = flatten([this.condition]); - for (_b = 0, _d = _c.length; _b < _d; _b++) { - cond = _c[_b]; - _a.push(cond.compile(o)); + _b = []; _d = flatten([this.condition]); + for (_c = 0, _e = _d.length; _c < _e; _c++) { + cond = _d[_c]; + _b.push(cond.compile(o)); } - return _a; + return _b; }).call(this).join(' || '); }; IfNode.prototype.compile_node = function compile_node(o) { diff --git a/lib/rewriter.js b/lib/rewriter.js index b5bd9f3b..b9b83641 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -1,5 +1,5 @@ (function(){ - var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, helpers, include, pair; + var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, helpers, include, pair; var __slice = Array.prototype.slice, __bind = function(func, obj, args) { return function() { return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments); @@ -19,7 +19,8 @@ helpers = this.helpers; } // Import the helpers we need. - include = helpers.include; + _a = helpers; + include = _a.include; // The **Rewriter** class is used by the [Lexer](lexer.html), directly against // its internal array of tokens. exports.Rewriter = (function() { @@ -62,13 +63,13 @@ // correctly indented, or appear on a line of their own. Rewriter.prototype.adjust_comments = function adjust_comments() { return this.scan_tokens(__bind(function(prev, token, post, i) { - var _a, after, before; + var _b, after, before; if (!(token[0] === 'COMMENT')) { return 1; } - _a = [this.tokens[i - 2], this.tokens[i + 2]]; - before = _a[0]; - after = _a[1]; + _b = [this.tokens[i - 2], this.tokens[i + 2]]; + before = _b[0]; + after = _b[1]; if (after && after[0] === 'INDENT') { this.tokens.splice(i + 2, 1); before && before[0] === 'OUTDENT' && post && (prev[0] === post[0]) && (post[0] === 'TERMINATOR') ? this.tokens.splice(i - 2, 1) : this.tokens.splice(i, 0, after); @@ -84,12 +85,12 @@ // Leading newlines would introduce an ambiguity in the grammar, so we // dispatch them here. Rewriter.prototype.remove_leading_newlines = function remove_leading_newlines() { - var _a; - _a = []; + var _b; + _b = []; while (this.tokens[0] && this.tokens[0][0] === 'TERMINATOR') { - _a.push(this.tokens.shift()); + _b.push(this.tokens.shift()); } - return _a; + return _b; }; // Some blocks occur in the middle of expressions -- when we're expecting // this, remove their trailing newlines. @@ -110,23 +111,23 @@ parens = [0]; brackets = [0]; return this.scan_tokens(__bind(function(prev, token, post, i) { - var _a; - if ((_a = token[0]) === 'CALL_START') { + var _b; + if ((_b = token[0]) === 'CALL_START') { parens.push(0); - } else if (_a === 'INDEX_START') { + } else if (_b === 'INDEX_START') { brackets.push(0); - } else if (_a === '(') { + } else if (_b === '(') { parens[parens.length - 1] += 1; - } else if (_a === '[') { + } else if (_b === '[') { brackets[brackets.length - 1] += 1; - } else if (_a === ')') { + } else if (_b === ')') { if (parens[parens.length - 1] === 0) { parens.pop(); token[0] = 'CALL_END'; } else { parens[parens.length - 1] -= 1; } - } else if (_a === ']') { + } else if (_b === ']') { if (brackets[brackets.length - 1] === 0) { brackets.pop(); token[0] = 'INDEX_END'; @@ -144,9 +145,9 @@ var close_calls, stack; stack = [0]; close_calls = __bind(function(i) { - var _a, _b, _c, size, tmp; - _b = 0; _c = stack[stack.length - 1]; - for (_a = 0, tmp = _b; (_b <= _c ? tmp < _c : tmp > _c); (_b <= _c ? tmp += 1 : tmp -= 1), _a++) { + var _b, _c, _d, size, tmp; + _c = 0; _d = stack[stack.length - 1]; + for (_b = 0, tmp = _c; (_c <= _d ? tmp < _d : tmp > _d); (_c <= _d ? tmp += 1 : tmp -= 1), _b++) { this.tokens.splice(i, 0, ['CALL_END', ')', this.tokens[i][2]]); } size = stack[stack.length - 1] + 1; @@ -235,17 +236,17 @@ // Ensure that all listed pairs of tokens are correctly balanced throughout // the course of the token stream. Rewriter.prototype.ensure_balance = function ensure_balance(pairs) { - var _a, _b, key, levels, line, open, open_line, unclosed, value; + var _b, _c, key, levels, line, open, open_line, unclosed, value; levels = {}; open_line = {}; this.scan_tokens(__bind(function(prev, token, post, i) { - var _a, _b, _c, _d, close, open, pair; - _b = pairs; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - pair = _b[_a]; - _d = pair; - open = _d[0]; - close = _d[1]; + var _b, _c, _d, _e, close, open, pair; + _c = pairs; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + pair = _c[_b]; + _e = pair; + open = _e[0]; + close = _e[1]; levels[open] = levels[open] || 0; if (token[0] === open) { if (levels[open] === 0) { @@ -263,12 +264,12 @@ return 1; }, this)); unclosed = (function() { - _a = []; _b = levels; - for (key in _b) { if (__hasProp.call(_b, key)) { - value = _b[key]; - value > 0 ? _a.push(key) : null; + _b = []; _c = levels; + for (key in _c) { if (__hasProp.call(_c, key)) { + value = _c[key]; + value > 0 ? _b.push(key) : null; }} - return _a; + return _b; })(); if (unclosed.length) { open = unclosed[0]; @@ -290,12 +291,12 @@ // 4. Be careful not to alter array or parentheses delimiters with overzealous // rewriting. Rewriter.prototype.rewrite_closing_parens = function rewrite_closing_parens() { - var _a, debt, key, stack, val; + var _b, debt, key, stack, val; stack = []; debt = {}; - _a = INVERSES; - for (key in _a) { if (__hasProp.call(_a, key)) { - val = _a[key]; + _b = INVERSES; + for (key in _b) { if (__hasProp.call(_b, key)) { + val = _b[key]; (debt[key] = 0); }} return this.scan_tokens(__bind(function(prev, token, post, i) { @@ -341,29 +342,29 @@ // The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can // look things up from either end. INVERSES = {}; - _b = BALANCED_PAIRS; - for (_a = 0, _c = _b.length; _a < _c; _a++) { - pair = _b[_a]; + _c = BALANCED_PAIRS; + for (_b = 0, _d = _c.length; _b < _d; _b++) { + pair = _c[_b]; INVERSES[pair[0]] = pair[1]; INVERSES[pair[1]] = pair[0]; } // The tokens that signal the start of a balanced pair. EXPRESSION_START = (function() { - _d = []; _f = BALANCED_PAIRS; - for (_e = 0, _g = _f.length; _e < _g; _e++) { - pair = _f[_e]; - _d.push(pair[0]); + _e = []; _g = BALANCED_PAIRS; + for (_f = 0, _h = _g.length; _f < _h; _f++) { + pair = _g[_f]; + _e.push(pair[0]); } - return _d; + return _e; })(); // The tokens that signal the end of a balanced pair. EXPRESSION_END = (function() { - _h = []; _j = BALANCED_PAIRS; - for (_i = 0, _k = _j.length; _i < _k; _i++) { - pair = _j[_i]; - _h.push(pair[1]); + _i = []; _k = BALANCED_PAIRS; + for (_j = 0, _l = _k.length; _j < _l; _j++) { + pair = _k[_j]; + _i.push(pair[1]); } - return _h; + return _i; })(); // Tokens that indicate the close of a clause of an expression. EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); diff --git a/src/command.coffee b/src/command.coffee index 3e95c698..08d7d473 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -5,11 +5,11 @@ # interactive REPL. # External dependencies. -fs: require 'fs' -path: require 'path' -optparse: require './optparse' -CoffeeScript: require './coffee-script' -{spawn: spawn, exec: exec}: require('child_process') +fs: require 'fs' +path: require 'path' +optparse: require './optparse' +CoffeeScript: require './coffee-script' +{spawn, exec}: require('child_process') # The help banner that is printed when `coffee` is called without arguments. BANNER: ''' @@ -123,7 +123,7 @@ write_js: (source, js) -> # Pipe compiled JS through JSLint (requires a working `jsl` command), printing # any errors or warnings that arise. lint: (js) -> - print_it: (buffer) -> puts buffer.toString() + print_it: (buffer) -> print buffer.toString() jsl: spawn 'jsl', ['-nologo', '-stdin'] jsl.stdout.addListener 'data', print_it jsl.stderr.addListener 'data', print_it diff --git a/src/lexer.coffee b/src/lexer.coffee index 1fba0572..6de5f202 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -17,11 +17,7 @@ else helpers: this.helpers # Import the helpers we need. -include: helpers.include -count: helpers.count -starts: helpers.starts -compact: helpers.compact -balanced_string: helpers.balanced_string +{include, count, starts, compact, balanced_string}: helpers # The Lexer Class # --------------- diff --git a/src/nodes.coffee b/src/nodes.coffee index 521c45f7..5d73d818 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -14,10 +14,7 @@ else Scope: this.Scope # Import the helpers we plan to use. -compact: helpers.compact -flatten: helpers.flatten -merge: helpers.merge -del: helpers.del +{compact, flatten, merge, del}: helpers # Helper function that marks a node as a JavaScript *statement*, or as a # *pure_statement*. Statements must be wrapped in a closure when used as an diff --git a/src/rewriter.coffee b/src/rewriter.coffee index b9a3a192..6f15c600 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -13,7 +13,7 @@ else helpers: this.helpers # Import the helpers we need. -include: helpers.include +{include}: helpers # The **Rewriter** class is used by the [Lexer](lexer.html), directly against # its internal array of tokens.