From 97096696a220bf4affdd7575a3541a78c5adbc0e Mon Sep 17 00:00:00 2001 From: matehat Date: Tue, 30 Mar 2010 16:48:43 -0400 Subject: [PATCH] Put back every utility functions on the global scope, automatically prefixed with `__` and set them dynamically as reserved on the lexer. --- lib/cake.js | 24 ++++----- lib/command.js | 23 ++++----- lib/grammar.js | 6 +-- lib/helpers.js | 10 ++-- lib/lexer.js | 13 +++-- lib/nodes.js | 113 +++++++++++++++++++++---------------------- lib/rewriter.js | 37 +++++++------- lib/scope.js | 27 +++++------ lib/utilities.js | 21 ++++---- src/lexer.coffee | 2 +- src/nodes.coffee | 6 +-- src/scope.coffee | 5 +- src/utilities.coffee | 17 ++++--- 13 files changed, 146 insertions(+), 158 deletions(-) diff --git a/lib/cake.js b/lib/cake.js index 587cbba2..a0b30b63 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -1,17 +1,13 @@ (function(){ var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks; - 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 - }; + var __slice = function(array, from, to, exclusive) { + return array.slice.apply(array, __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; // `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, @@ -64,7 +60,7 @@ if (!(exists)) { throw new Error("Cakefile not found in " + (process.cwd())); } - args = Coffeescript.slice(process.argv, 2, process.argv.length, true); + args = __slice(process.argv, 2, process.argv.length, true); CoffeeScript.run(fs.readFileSync('Cakefile'), { source: 'Cakefile' }); @@ -86,7 +82,7 @@ var _a, _b, _c, _d, _e, i, name, spaces, task; puts(''); _a = tasks; - for (name in _a) { if (Coffeescript.hasProp.call(_a, name)) { + for (name in _a) { if (__hasProp.call(_a, name)) { task = _a[name]; spaces = 20 - name.length; spaces = spaces > 0 ? (function() { diff --git a/lib/command.js b/lib/command.js index 39bc5b7b..9e9015e4 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,15 +1,12 @@ (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 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) - ]; - } + var __slice = function(array, from, to, exclusive) { + return array.slice.apply(array, __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) + ]; }; // The `coffee` utility. Handles command-line compilation of CoffeeScript // into various forms: saved into `.js` files or printed to stdout, piped to @@ -56,8 +53,8 @@ separator = sources.indexOf('--'); flags = []; if (separator >= 0) { - flags = Coffeescript.slice(sources, (separator + 1), sources.length, true); - sources = Coffeescript.slice(sources, 0, separator, true); + flags = __slice(sources, (separator + 1), sources.length, true); + sources = __slice(sources, 0, separator, true); } process.ARGV = (process.argv = flags); if (options.watch) { @@ -213,7 +210,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 = Coffeescript.slice(options.arguments, 2, options.arguments.length, true); + sources = __slice(options.arguments, 2, options.arguments.length, true); return sources; }; // The compile-time options to pass to the CoffeeScript compiler. diff --git a/lib/grammar.js b/lib/grammar.js index 53c2be9f..de57673c 100644 --- a/lib/grammar.js +++ b/lib/grammar.js @@ -1,8 +1,6 @@ (function(){ var Parser, _a, _b, _c, _d, _e, _f, _g, _h, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; - var Coffeescript = { - hasProp: Object.prototype.hasOwnProperty - }; + var __hasProp = Object.prototype.hasOwnProperty; // The CoffeeScript parser is generated by [Jison](http://github.com/zaach/jison) // from this grammar file. Jison is a bottom-up parser generator, similar in // style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript. @@ -674,7 +672,7 @@ // as "tokens". tokens = []; _a = grammar; - for (name in _a) { if (Coffeescript.hasProp.call(_a, name)) { + for (name in _a) { if (__hasProp.call(_a, name)) { alternatives = _a[name]; grammar[name] = (function() { _b = []; _d = alternatives; diff --git a/lib/helpers.js b/lib/helpers.js index f8b67a6c..d262227f 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,8 +1,6 @@ (function(){ var balanced_string, compact, count, del, extend, flatten, helpers, include, merge, starts; - var Coffeescript = { - hasProp: Object.prototype.hasOwnProperty - }; + var __hasProp = Object.prototype.hasOwnProperty; // This file contains the common helper functions that we'd like to share among // the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten // arrays, count characters, that sort of thing. @@ -47,13 +45,13 @@ var _a, _b, fresh, key, val; fresh = {}; _a = options; - for (key in _a) { if (Coffeescript.hasProp.call(_a, key)) { + for (key in _a) { if (__hasProp.call(_a, key)) { val = _a[key]; (fresh[key] = val); }} if (overrides) { _b = overrides; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { + for (key in _b) { if (__hasProp.call(_b, key)) { val = _b[key]; (fresh[key] = val); }} @@ -65,7 +63,7 @@ helpers.extend = (extend = function extend(object, properties) { var _a, _b, key, val; _a = []; _b = properties; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { + for (key in _b) { if (__hasProp.call(_b, key)) { val = _b[key]; _a.push((object[key] = val)); }} diff --git a/lib/lexer.js b/lib/lexer.js index a6f8e657..90914b17 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -1,5 +1,6 @@ (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, _b, _c, _d, balanced_string, compact, count, helpers, include, k, starts, u; + var __arraySlice = Array.prototype.slice, __hasProp = Object.prototype.hasOwnProperty; // 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, // a token is produced, we consume the match, and start again. Tokens are in the @@ -236,7 +237,7 @@ // balanced (ie. strings, JS literals). Lexer.prototype.balanced_token = function balanced_token() { var delimited; - delimited = Array.prototype.slice.call(arguments, 0, arguments.length - 0); + delimited = __arraySlice.call(arguments, 0, arguments.length - 0); return balanced_string(this.chunk, delimited); }; // Matches and conumes comments. We pass through comments into JavaScript, @@ -609,7 +610,13 @@ // The list of keywords that are reserved by JavaScript, but not used, or are // used by CoffeeScript internally. We throw an error when these are encountered, // to avoid having a JavaScript error at runtime. - RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "debugger", "enum", "export", "import", "native", "Coffeescript"]; + RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "debugger", "enum", "export", "import", "native"].concat((function() { + _c = []; _d = (u = require('./utilities')).utilities.functions; + for (k in _d) { if (__hasProp.call(_d, k)) { + _c.push(u.utilities.key(k)); + }} + return _c; + }).call(this)); // The superset of both JavaScript keywords and reserved words, none of which may // be used as identifiers or properties. JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED); diff --git a/lib/nodes.js b/lib/nodes.js index 2210eb92..b05fc481 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1,31 +1,26 @@ (function(){ var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, helpers, literal, merge, statement; - var Coffeescript = { - extend: function(child, parent) { - var ctor = function(){ }; - ctor.prototype = parent.prototype; - child.__superClass__ = parent.prototype; - child.prototype = new ctor(); - 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) { - obj = obj || {}; - return (typeof args !== 'undefined' && args !== null) ? function() { - return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0))); - } : function() { - return func.apply(obj, arguments); - }; - } - }; + var __extend = function(child, parent) { + var ctor = function(){ }; + ctor.prototype = parent.prototype; + child.__superClass__ = parent.prototype; + child.prototype = new ctor(); + child.prototype.constructor = child; + }, __slice = function(array, from, to, exclusive) { + return array.slice.apply(array, __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) { + obj = obj || {}; + return (typeof args !== 'undefined' && args !== null) ? function() { + return func.apply(obj, args.concat(__arraySlice.call(arguments, 0))); + } : function() { + return func.apply(obj, arguments); + }; + }, __arraySlice = Array.prototype.slice; // `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), // but some are created by other nodes as a method of code generation. To convert @@ -208,7 +203,7 @@ this.children = (this.expressions = compact(flatten(nodes || []))); return this; }; - Coffeescript.extend(Expressions, BaseNode); + __extend(Expressions, BaseNode); Expressions.prototype.type = 'Expressions'; // Tack an expression on to the end of this expression list. Expressions.prototype.push = function push(node) { @@ -336,7 +331,7 @@ this.value = value; return this; }; - Coffeescript.extend(LiteralNode, BaseNode); + __extend(LiteralNode, BaseNode); LiteralNode.prototype.type = 'Literal'; // Break and continue must be treated as pure statements -- they lose their // meaning when wrapped in a closure. @@ -363,7 +358,7 @@ this.children = [(this.expression = expression)]; return this; }; - Coffeescript.extend(ReturnNode, BaseNode); + __extend(ReturnNode, BaseNode); ReturnNode.prototype.type = 'Return'; ReturnNode.prototype.top_sensitive = function top_sensitive() { return true; @@ -391,7 +386,7 @@ this.children = flatten([(this.base = base), (this.properties = (properties || []))]); return this; }; - Coffeescript.extend(ValueNode, BaseNode); + __extend(ValueNode, BaseNode); ValueNode.prototype.type = 'Value'; ValueNode.prototype.SOAK = " == undefined ? undefined : "; // A **ValueNode** has a base and a list of property accesses. @@ -445,7 +440,7 @@ op = del(o, 'operation'); splice = del(o, 'splice'); replace = del(o, 'replace'); - props = only ? Coffeescript.slice(this.properties, 0, this.properties.length - 1, true) : this.properties; + 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 + ")"; @@ -498,7 +493,7 @@ this; return this; }; - Coffeescript.extend(CommentNode, BaseNode); + __extend(CommentNode, BaseNode); CommentNode.prototype.type = 'Comment'; CommentNode.prototype.make_return = function make_return() { return this; @@ -518,10 +513,10 @@ this.is_super = variable === 'super'; this.variable = this.is_super ? null : variable; this.children = compact(flatten([this.variable, (this.args = (args || []))])); - this.compile_splat_arguments = Coffeescript.bind(SplatNode.compile_mixed_array, this, [this.args]); + this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]); return this; }; - Coffeescript.extend(CallNode, BaseNode); + __extend(CallNode, BaseNode); CallNode.prototype.type = 'Call'; // Tag this invocation as creating a new instance. CallNode.prototype.new_instance = function new_instance() { @@ -588,10 +583,10 @@ exports.CurryNode = (function() { CurryNode = function CurryNode(meth, args) { this.children = flatten([(this.meth = meth), (this.context = args[0]), (this.args = (args.slice(1) || []))]); - this.compile_splat_arguments = Coffeescript.bind(SplatNode.compile_mixed_array, this, [this.args]); + this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]); return this; }; - Coffeescript.extend(CurryNode, CallNode); + __extend(CurryNode, CallNode); CurryNode.prototype.type = 'Curry'; CurryNode.prototype.arguments = function arguments(o) { var _a, _b, _c, arg; @@ -620,7 +615,7 @@ this.children = [(this.child = child), (this.parent = parent)]; return this; }; - Coffeescript.extend(ExtendsNode, BaseNode); + __extend(ExtendsNode, BaseNode); ExtendsNode.prototype.type = 'Extends'; // Hooks one constructor into another's prototype chain. ExtendsNode.prototype.compile_node = function compile_node(o) { @@ -641,7 +636,7 @@ this; return this; }; - Coffeescript.extend(AccessorNode, BaseNode); + __extend(AccessorNode, BaseNode); AccessorNode.prototype.type = 'Accessor'; AccessorNode.prototype.compile_node = function compile_node(o) { var proto_part; @@ -658,7 +653,7 @@ this.soak_node = tag === 'soak'; return this; }; - Coffeescript.extend(IndexNode, BaseNode); + __extend(IndexNode, BaseNode); IndexNode.prototype.type = 'Index'; IndexNode.prototype.compile_node = function compile_node(o) { var idx; @@ -677,7 +672,7 @@ this.exclusive = !!exclusive; return this; }; - Coffeescript.extend(RangeNode, BaseNode); + __extend(RangeNode, BaseNode); RangeNode.prototype.type = 'Range'; // Compiles the range's source variables -- where it starts and where it ends. RangeNode.prototype.compile_variables = function compile_variables(o) { @@ -733,7 +728,7 @@ this; return this; }; - Coffeescript.extend(SliceNode, BaseNode); + __extend(SliceNode, BaseNode); SliceNode.prototype.type = 'Slice'; SliceNode.prototype.compile_node = function compile_node(o) { var from, plus_part, to; @@ -772,7 +767,7 @@ this.children = (this.objects = (this.properties = props || [])); return this; }; - Coffeescript.extend(ObjectNode, BaseNode); + __extend(ObjectNode, BaseNode); ObjectNode.prototype.type = 'Object'; // All the mucking about with commas is to make sure that CommentNodes and // AssignNodes get interleaved correctly, with no trailing commas or @@ -819,10 +814,10 @@ exports.ArrayNode = (function() { ArrayNode = function ArrayNode(objects) { this.children = (this.objects = objects || []); - this.compile_splat_literal = Coffeescript.bind(SplatNode.compile_mixed_array, this, [this.objects]); + this.compile_splat_literal = __bind(SplatNode.compile_mixed_array, this, [this.objects]); return this; }; - Coffeescript.extend(ArrayNode, BaseNode); + __extend(ArrayNode, BaseNode); ArrayNode.prototype.type = 'Array'; ArrayNode.prototype.compile_node = function compile_node(o) { var _a, _b, code, ending, i, obj, objects; @@ -856,7 +851,7 @@ this.returns = false; return this; }; - Coffeescript.extend(ClassNode, BaseNode); + __extend(ClassNode, BaseNode); ClassNode.prototype.type = 'Class'; // Initialize a **ClassNode** with its name, an optional superclass, and a // list of prototype property assignments. @@ -916,7 +911,7 @@ this.context = context; return this; }; - Coffeescript.extend(AssignNode, BaseNode); + __extend(AssignNode, BaseNode); AssignNode.prototype.type = 'Assign'; // Matchers for detecting prototype assignments. AssignNode.prototype.PROTO_ASSIGN = /^(\S+)\.prototype/; @@ -1034,7 +1029,7 @@ this.bound = tag === 'boundfunc'; return this; }; - Coffeescript.extend(CodeNode, BaseNode); + __extend(CodeNode, BaseNode); CodeNode.prototype.type = 'Code'; // Compilation creates a new scope unless explicitly asked to share with the // outer scope. Handles splat parameters in the parameter list by peeking at @@ -1139,7 +1134,7 @@ this.children = [(this.name = name)]; return this; }; - Coffeescript.extend(SplatNode, BaseNode); + __extend(SplatNode, BaseNode); SplatNode.prototype.type = 'Splat'; SplatNode.prototype.compile_node = function compile_node(o) { var _a; @@ -1162,15 +1157,15 @@ o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]"); i += 1; } - return "" + name + " = Array.prototype.slice.call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")"; + return "" + name + " = " + (o.scope.utility('arraySlice')) + ".call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")"; }; // A compiling a splat as a destructuring assignment means slicing arguments // from the right-hand-side's corresponding array. SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) { if ((typeof trailings !== "undefined" && trailings !== null)) { - return "Array.prototype.slice.call(" + name + ", " + index + ", " + (name) + ".length - " + trailings + ")"; + return "" + (o.scope.utility('arraySlice')) + ".call(" + name + ", " + index + ", " + (name) + ".length - " + trailings + ")"; } else { - return "Array.prototype.slice.call(" + name + ", " + index + ")"; + return "" + (o.scope.utility('arraySlice')) + ".call(" + name + ", " + index + ")"; } }; // Utility function that converts arbitrary number of elements, mixed with @@ -1212,7 +1207,7 @@ this.filter = opts && opts.filter; return this; }; - Coffeescript.extend(WhileNode, BaseNode); + __extend(WhileNode, BaseNode); WhileNode.prototype.type = 'While'; WhileNode.prototype.add_body = function add_body(body) { this.children.push((this.body = body)); @@ -1268,7 +1263,7 @@ this.flip = !!flip; return this; }; - Coffeescript.extend(OpNode, BaseNode); + __extend(OpNode, BaseNode); OpNode.prototype.type = 'Op'; // The map of conversions from CoffeeScript to JavaScript symbols. OpNode.prototype.CONVERSIONS = { @@ -1369,7 +1364,7 @@ this; return this; }; - Coffeescript.extend(TryNode, BaseNode); + __extend(TryNode, BaseNode); TryNode.prototype.type = 'Try'; TryNode.prototype.make_return = function make_return() { if (this.attempt) { @@ -1402,7 +1397,7 @@ this.children = [(this.expression = expression)]; return this; }; - Coffeescript.extend(ThrowNode, BaseNode); + __extend(ThrowNode, BaseNode); ThrowNode.prototype.type = 'Throw'; // A **ThrowNode** is already a return, of sorts... ThrowNode.prototype.make_return = function make_return() { @@ -1423,7 +1418,7 @@ this.children = [(this.expression = expression)]; return this; }; - Coffeescript.extend(ExistenceNode, BaseNode); + __extend(ExistenceNode, BaseNode); ExistenceNode.prototype.type = 'Existence'; ExistenceNode.prototype.compile_node = function compile_node(o) { return ExistenceNode.compile_test(o, this.expression); @@ -1458,7 +1453,7 @@ this.children = [(this.expression = expression)]; return this; }; - Coffeescript.extend(ParentheticalNode, BaseNode); + __extend(ParentheticalNode, BaseNode); ParentheticalNode.prototype.type = 'Paren'; ParentheticalNode.prototype.is_statement = function is_statement() { return this.expression.is_statement(); @@ -1510,7 +1505,7 @@ this.returns = false; return this; }; - Coffeescript.extend(ForNode, BaseNode); + __extend(ForNode, BaseNode); ForNode.prototype.type = 'For'; ForNode.prototype.top_sensitive = function top_sensitive() { return true; @@ -1614,7 +1609,7 @@ } return this; }; - Coffeescript.extend(IfNode, BaseNode); + __extend(IfNode, BaseNode); IfNode.prototype.type = 'If'; // Add a new *else* clause to this **IfNode**, or push it down to the bottom // of the chain recursively. diff --git a/lib/rewriter.js b/lib/rewriter.js index 104f602d..3f169074 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -1,16 +1,13 @@ (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 Coffeescript = { - bind: function(func, obj, args) { - obj = obj || {}; - return (typeof args !== 'undefined' && args !== null) ? function() { - return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0))); - } : function() { - return func.apply(obj, arguments); - }; - }, - hasProp: Object.prototype.hasOwnProperty - }; + var __bind = function(func, obj, args) { + obj = obj || {}; + return (typeof args !== 'undefined' && args !== null) ? function() { + return func.apply(obj, args.concat(__arraySlice.call(arguments, 0))); + } : function() { + return func.apply(obj, arguments); + }; + }, __arraySlice = Array.prototype.slice, __hasProp = Object.prototype.hasOwnProperty; // The CoffeeScript language has a good deal of optional syntax, implicit syntax, // and shorthand syntax. This can greatly complicate a grammar and bloat // the resulting parse table. Instead of making the parser handle it all, we take @@ -67,7 +64,7 @@ // Massage newlines and indentations so that comments don't have to be // correctly indented, or appear on a line of their own. Rewriter.prototype.adjust_comments = function adjust_comments() { - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { var after; if (!(token[0] === 'COMMENT')) { return 1; @@ -98,7 +95,7 @@ // Some blocks occur in the middle of expressions -- when we're expecting // this, remove their trailing newlines. Rewriter.prototype.remove_mid_expression_newlines = function remove_mid_expression_newlines() { - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { if (!(post && include(EXPRESSION_CLOSE, post[0]) && token[0] === 'TERMINATOR')) { return 1; } @@ -113,7 +110,7 @@ var brackets, parens; parens = [0]; brackets = [0]; - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { var _a; if ((_a = token[0]) === 'CALL_START') { parens.push(0); @@ -149,7 +146,7 @@ stack = [0]; calls = 0; parens = 0; - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { var _a, _b, _c, idx, last, open, size, stack_pointer, tag, tmp; tag = token[0]; if (tag === 'CALL_START') { @@ -200,7 +197,7 @@ // blocks, so it doesn't need to. ')' can close a single-line block, // but we need to make sure it's balanced. Rewriter.prototype.add_implicit_indentation = function add_implicit_indentation() { - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { var idx, insertion, outdent, parens, pre, starter, tok; if (!(include(SINGLE_LINERS, token[0]) && post[0] !== 'INDENT' && !(token[0] === 'ELSE' && post[0] === 'IF'))) { return 1; @@ -240,7 +237,7 @@ var _a, _b, key, levels, line, open, open_line, unclosed, value; levels = {}; open_line = {}; - this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + 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++) { @@ -266,7 +263,7 @@ }, this)); unclosed = (function() { _a = []; _b = levels; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { + for (key in _b) { if (__hasProp.call(_b, key)) { value = _b[key]; value > 0 ? _a.push(key) : null; }} @@ -294,11 +291,11 @@ stack = []; debt = {}; _a = INVERSES; - for (key in _a) { if (Coffeescript.hasProp.call(_a, key)) { + for (key in _a) { if (__hasProp.call(_a, key)) { val = _a[key]; (debt[key] = 0); }} - return this.scan_tokens(Coffeescript.bind(function(prev, token, post, i) { + return this.scan_tokens(__bind(function(prev, token, post, i) { var inv, match, mtag, tag; tag = token[0]; inv = INVERSES[token[0]]; diff --git a/lib/scope.js b/lib/scope.js index 7382fc82..ef7cf093 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -1,8 +1,6 @@ (function(){ var Scope, utilities; - var Coffeescript = { - hasProp: Object.prototype.hasOwnProperty - }; + var __hasProp = Object.prototype.hasOwnProperty; // The **Scope** class regulates lexical scoping within CoffeeScript. As you // generate code, you create a tree of scopes in the same shape as the nested // function bodies. Each scope knows about the variables declared within it, @@ -50,7 +48,7 @@ Scope.prototype.any = function any(fn) { var _a, k, v; _a = this.variables; - for (v in _a) { if (Coffeescript.hasProp.call(_a, v)) { + for (v in _a) { if (__hasProp.call(_a, v)) { k = _a[v]; if (fn(v, k)) { return true; @@ -110,21 +108,18 @@ !this.utilities[dep] ? this.utility(dep) : null; } } - 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) { - var _a, _b, _c, key, props; + var _a, _b, _c, key; if ((typeof (_c = this.utilities) !== "undefined" && _c !== null)) { - props = (function() { - _a = []; _b = this.utilities; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { - _a.push(utilities.format(key, tab)); - }} - return _a; - }).call(this); - return ["" + (utilities.key) + " = {" + (props.join(', ')) + "\n" + tab + "}"]; + _a = []; _b = this.utilities; + for (key in _b) { if (__hasProp.call(_b, key)) { + _a.push(utilities.format(key, tab)); + }} + return _a; } else { return []; } @@ -149,7 +144,7 @@ var _a, _b, key, val; return (function() { _a = []; _b = this.variables; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { + for (key in _b) { if (__hasProp.call(_b, key)) { val = _b[key]; val === 'var' ? _a.push(key) : null; }} @@ -161,7 +156,7 @@ Scope.prototype.assigned_variables = function assigned_variables() { var _a, _b, key, val; _a = []; _b = this.variables; - for (key in _b) { if (Coffeescript.hasProp.call(_b, key)) { + for (key in _b) { if (__hasProp.call(_b, key)) { val = _b[key]; val.assigned ? _a.push("" + key + " = " + (val.value)) : null; }} diff --git a/lib/utilities.js b/lib/utilities.js index 51a13cbb..9a2b82fd 100644 --- a/lib/utilities.js +++ b/lib/utilities.js @@ -1,26 +1,29 @@ (function(){ - var KEY, utilities; + var utilities; if (!((typeof process !== "undefined" && process !== null))) { this.exports = this; } - KEY = "Coffeescript"; exports.utilities = (function() { utilities = function utilities() { }; - utilities.key = KEY; + utilities.key = function key(name) { + return "__" + name; + }; utilities.format = function format(key, tab) { - return "\n " + tab + key + ": " + (utilities.functions[key].replace(/\n/g, "\n" + tab + " ") || 'undefined'); + return "" + (utilities.key(key)) + " = " + (utilities.functions[key].replace(/\n/g, "\n" + tab) || 'undefined'); }; utilities.dependencies = { slice: ['range'], - splice: ['range'] + splice: ['range'], + bind: ['arraySlice'] }; 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(Array.prototype.slice.call(arguments, 0)));\n } : function() {\n return func.apply(obj, arguments);\n };\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('arraySlice')) + ".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, " + (KEY) + ".range(array, from, to, exclusive));\n}", - splice: "function(array, from, to, exclusive, replace) {\n return array.splice.apply(array, [(_a = " + (KEY) + ".range(array, from, to, exclusive))[0], \n _a[1] - _a[0]].concat(replace));\n}", - hasProp: "Object.prototype.hasOwnProperty" + 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 return array.splice.apply(array, [(_a = " + (utilities.key('range')) + "(array, from, to, exclusive))[0], \n _a[1] - _a[0]].concat(replace));\n}", + hasProp: 'Object.prototype.hasOwnProperty', + arraySlice: 'Array.prototype.slice' }; return utilities; }).call(this); diff --git a/src/lexer.coffee b/src/lexer.coffee index a0b9fafd..64543c98 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -464,7 +464,7 @@ KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS RESERVED: [ "case", "default", "do", "function", "var", "void", "with" "const", "let", "debugger", "enum", "export", "import", "native", - "Coffeescript" + (u.utilities.key(k) for k of (u: require './utilities').utilities.functions)... ] # The superset of both JavaScript keywords and reserved words, none of which may diff --git a/src/nodes.coffee b/src/nodes.coffee index fcabd953..4a4666c9 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -843,13 +843,13 @@ exports.SplatNode: class SplatNode extends BaseNode for trailing in @trailings o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]") i: + 1 - "$name = Array.prototype.slice.call(arguments, $@index, arguments.length - ${@trailings.length})" + "$name = ${o.scope.utility('arraySlice')}.call(arguments, $@index, arguments.length - ${@trailings.length})" # A compiling a splat as a destructuring assignment means slicing arguments # from the right-hand-side's corresponding array. compile_value: (o, name, index, trailings) -> - if trailings? then "Array.prototype.slice.call($name, $index, ${name}.length - $trailings)" \ - else "Array.prototype.slice.call($name, $index)" + if trailings? then "${o.scope.utility('arraySlice')}.call($name, $index, ${name}.length - $trailings)" \ + else "${o.scope.utility('arraySlice')}.call($name, $index)" # Utility function that converts arbitrary number of elements, mixed with # splats, to a proper array diff --git a/src/scope.coffee b/src/scope.coffee index 3f60ced6..c7a041a4 100644 --- a/src/scope.coffee +++ b/src/scope.coffee @@ -70,14 +70,13 @@ exports.Scope: class Scope @utilities: or {} @utilities[name]: utilities.functions[name] @utility(dep) for dep in (utilities.dependencies[name] or []) when not @utilities[dep] - "${utilities.key}.$name" + "${utilities.key(name)}" # Formats an javascript object containing the utility methods required # in the scope included_utilities: (tab) -> if @utilities? - props: (utilities.format(key, tab) for key of @utilities) - ["${utilities.key} = {${props.join(', ')}\n$tab}"] + utilities.format(key, tab) for key of @utilities else [] # Does this scope reference any variables that need to be declared in the diff --git a/src/utilities.coffee b/src/utilities.coffee index f22e1d2a..c562fc29 100644 --- a/src/utilities.coffee +++ b/src/utilities.coffee @@ -1,14 +1,16 @@ this.exports: this unless process? -KEY: "Coffeescript" exports.utilities: class utilities - @key: KEY + @key: (name) -> + "__$name" + @format: (key, tab) -> - "\n $tab$key: ${utilities.functions[key].replace(/\n/g, "\n$tab ") or 'undefined'}" + "${utilities.key(key)} = ${utilities.functions[key].replace(/\n/g, "\n$tab") or 'undefined'}" @dependencies: { slice: ['range'] splice: ['range'] + bind: ['arraySlice'] } @functions: { @@ -25,7 +27,7 @@ exports.utilities: class utilities function(func, obj, args) { obj = obj || {}; 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('arraySlice')}.call(arguments, 0))); } : function() { return func.apply(obj, arguments); }; @@ -41,14 +43,15 @@ exports.utilities: class utilities """ slice: """ function(array, from, to, exclusive) { - return array.slice.apply(array, ${KEY}.range(array, from, to, exclusive)); + return array.slice.apply(array, ${utilities.key('range')}(array, from, to, exclusive)); } """ splice: """ function(array, from, to, exclusive, replace) { - return array.splice.apply(array, [(_a = ${KEY}.range(array, from, to, exclusive))[0], + return array.splice.apply(array, [(_a = ${utilities.key('range')}(array, from, to, exclusive))[0], _a[1] - _a[0]].concat(replace)); } """ - hasProp: "Object.prototype.hasOwnProperty" + hasProp: 'Object.prototype.hasOwnProperty' + arraySlice: 'Array.prototype.slice' } \ No newline at end of file