Merge branch 'master' into newline-splat

Conflicts:
	lib/lexer.js
	lib/parser.js
	src/lexer.coffee
This commit is contained in:
Sam Stephenson 2010-10-11 12:12:13 -05:00
commit 967fec2ae5
22 changed files with 451 additions and 910 deletions

View File

@ -2,7 +2,7 @@ require 'erb'
require 'fileutils'
require 'rake/testtask'
require 'rubygems'
require 'closure-compiler'
require 'yui/compressor'
HEADER = <<-EOS
/**
@ -42,7 +42,7 @@ task :browser do
}
JS
end
code = Closure::Compiler.new.compress(<<-"JS")
code = YUI::JavaScriptCompressor.new.compress(<<-"JS")
this.CoffeeScript = function(){
function require(path){ return require[path] }
#{ code }

View File

@ -1309,7 +1309,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
source = $('#repl_source').val()
window.compiled_js = ''
try
window.compiled_js = CoffeeScript.compile source, noWrap: true
window.compiled_js = CoffeeScript.compile source, wrap: false
$('#repl_results').text window.compiled_js
$('#error').hide()
catch error

File diff suppressed because one or more lines are too long

View File

@ -2170,7 +2170,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
source = $('#repl_source').val()
window.compiled_js = ''
try
window.compiled_js = CoffeeScript.compile source, noWrap: true
window.compiled_js = CoffeeScript.compile source, wrap: false
$('#repl_results').text window.compiled_js
$('#error').hide()
catch error

View File

@ -215,7 +215,7 @@
o = {
fileName: fileName
};
o.noWrap = opts['no-wrap'];
o.wrap = !opts['no-wrap'];
return o;
};
usage = function() {

View File

@ -64,12 +64,8 @@
return new Literal($1);
}), o("REGEX", function() {
return new Literal($1);
}), o("TRUE", function() {
return new Literal(true);
}), o("FALSE", function() {
return new Literal(false);
}), o("NULL", function() {
return new Literal('null');
}), o("BOOL", function() {
return new Literal($1);
})
],
Assign: [
@ -130,7 +126,7 @@
}), o("Param", function() {
return [$1];
}), o("ParamList , Param", function() {
return $1.concat([$3]);
return $1.concat($3);
})
],
Param: [
@ -209,9 +205,9 @@
}), o("AssignObj", function() {
return [$1];
}), o("AssignList , AssignObj", function() {
return $1.concat([$3]);
return $1.concat($3);
}), o("AssignList OptComma TERMINATOR AssignObj", function() {
return $1.concat([$4]);
return $1.concat($4);
}), o("AssignList OptComma INDENT AssignList OptComma OUTDENT", function() {
return $1.concat($4);
})
@ -329,9 +325,9 @@
o("Arg", function() {
return [$1];
}), o("ArgList , Arg", function() {
return $1.concat([$3]);
return $1.concat($3);
}), o("ArgList OptComma TERMINATOR Arg", function() {
return $1.concat([$4]);
return $1.concat($4);
}), o("INDENT ArgList OptComma OUTDENT", function() {
return $2;
}), o("ArgList OptComma INDENT ArgList OptComma OUTDENT", function() {
@ -341,7 +337,7 @@
Arg: [o("Expression"), o("Splat")],
SimpleArgs: [
o("Expression"), o("SimpleArgs , Expression", function() {
return $1 instanceof Array ? $1.concat([$3]) : [$1].concat([$3]);
return [].concat($1, $3);
})
],
Try: [

View File

@ -1,10 +1,11 @@
(function() {
var ASSIGNED, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_SPACES, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NEXT_ELLIPSIS, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, _ref, compact, count, include, last, op, starts;
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_SPACES, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NEXT_ELLIPSIS, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, _ref, compact, count, include, last, op, starts;
Rewriter = require('./rewriter').Rewriter;
_ref = require('./helpers'), include = _ref.include, count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
exports.Lexer = (function() {
Lexer = (function() {
return function Lexer() {};
function Lexer() {};
return Lexer;
})();
Lexer.prototype.tokenize = function(code, options) {
var o;
@ -19,7 +20,7 @@
this.seenFor = false;
this.indents = [];
this.tokens = [];
while ((this.chunk = code.slice(this.i))) {
while (this.chunk = code.slice(this.i)) {
this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
}
this.closeIndentation();
@ -29,17 +30,17 @@
return (new Rewriter).rewrite(this.tokens);
};
Lexer.prototype.identifierToken = function() {
var forcedIdentifier, id, match, tag;
var _ref2, colon, forcedIdentifier, id, input, match, tag;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return false;
}
id = match[0];
this.i += id.length;
_ref2 = match, input = _ref2[0], id = _ref2[1], colon = _ref2[2];
this.i += input.length;
if (id === 'all' && this.tag() === 'FOR') {
this.token('ALL', id);
return true;
}
forcedIdentifier = this.tagAccessor() || ASSIGNED.test(this.chunk);
forcedIdentifier = colon || this.tagAccessor();
tag = 'IDENTIFIER';
if (include(JS_KEYWORDS, id) || !forcedIdentifier && include(COFFEE_KEYWORDS, id)) {
tag = id.toUpperCase();
@ -79,9 +80,15 @@
tag = 'UNARY';
} else if (include(LOGIC, id)) {
tag = 'LOGIC';
} else if (include(BOOL, tag)) {
id = tag.toLowerCase();
tag = 'BOOL';
}
}
this.token(tag, id);
if (colon) {
this.token(':', ':');
}
return true;
};
Lexer.prototype.numberToken = function() {
@ -330,9 +337,9 @@
if (!prev[1].reserved && include(JS_FORBIDDEN, prev[1])) {
this.assignmentError();
}
if (('or' === (_ref2 = prev[1]) || 'and' === _ref2)) {
if (('||' === (_ref2 = prev[1]) || '&&' === _ref2)) {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] = COFFEE_ALIASES[prev[1]] + '=';
prev[1] += '=';
return true;
}
}
@ -374,25 +381,23 @@
return true;
};
Lexer.prototype.tagAccessor = function() {
var accessor, prev;
var prev;
if (!(prev = last(this.tokens)) || prev.spaced) {
return false;
}
accessor = (function() {
if (prev[1] === '::') {
return this.tag(0, 'PROTOTYPE_ACCESS');
} else if (prev[1] === '.' && this.value(1) !== '.') {
if (this.tag(1) === '?') {
this.tag(0, 'SOAK_ACCESS');
return this.tokens.splice(-2, 1);
} else {
return this.tag(0, 'PROPERTY_ACCESS');
}
if (prev[1] === '::') {
this.tag(0, 'PROTOTYPE_ACCESS');
} else if (prev[1] === '.' && this.value(1) !== '.') {
if (this.tag(1) === '?') {
this.tag(0, 'SOAK_ACCESS');
this.tokens.splice(-2, 1);
} else {
return prev[0] === '@';
this.tag(0, 'PROPERTY_ACCESS');
}
}).call(this);
return accessor ? 'accessor' : false;
} else {
return prev[0] === '@';
}
return true;
};
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
var _ref2, _ref3, attempt, herecomment, indent, match;
@ -422,10 +427,7 @@
return;
}
i = this.tokens.length;
while (true) {
if (!(tok = this.tokens[--i])) {
return;
}
while (tok = this.tokens[--i]) {
switch (tok[0]) {
case 'IDENTIFIER':
tok[0] = 'PARAM';
@ -435,7 +437,8 @@
break;
case '(':
case 'CALL_START':
return (tok[0] = 'PARAM_START');
tok[0] = 'PARAM_START';
return true;
}
}
return true;
@ -444,10 +447,10 @@
return this.outdentToken(this.indent);
};
Lexer.prototype.identifierError = function(word) {
throw new Error("SyntaxError: Reserved word \"" + word + "\" on line " + (this.line + 1));
throw SyntaxError("Reserved word \"" + word + "\" on line " + (this.line + 1));
};
Lexer.prototype.assignmentError = function() {
throw new Error("SyntaxError: Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
};
Lexer.prototype.balancedString = function(str, delimited, options) {
var _i, _len, _ref2, close, i, levels, open, pair, slen;
@ -596,7 +599,7 @@
COFFEE_ALIASES['==='] = '==';
RESERVED = ['case', 'default', 'do', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice'];
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
IDENTIFIER = /^[a-zA-Z_$][\w$]*/;
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/;
OPERATOR = /^(?:-[-=>]?|\+[+=]?|\.\.\.?|[*&|\/%=<>^:!?]+)/;
@ -624,7 +627,8 @@
COMPARE = ['<=', '<', '>', '>='];
MATH = ['*', '/', '%'];
RELATION = ['IN', 'OF', 'INSTANCEOF'];
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'];
BOOL = ['TRUE', 'FALSE', 'NULL'];
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']'];
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::'];
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
}).call(this);

View File

@ -1,5 +1,5 @@
(function() {
var Accessor, ArrayLiteral, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, Literal, NO, NUMBER, ObjectLiteral, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, _ref, compact, del, ends, flatten, include, indexOf, last, merge, starts, utility;
var Accessor, ArrayLiteral, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, Literal, NO, NUMBER, ObjectLiteral, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, _ref, compact, del, ends, flatten, include, last, merge, starts, utility;
var __extends = function(child, parent) {
var ctor = function() {};
ctor.prototype = parent.prototype;
@ -9,7 +9,7 @@
child.__super__ = parent.prototype;
};
Scope = require('./scope').Scope;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, indexOf = _ref.indexOf, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
YES = function() {
return true;
};
@ -21,10 +21,11 @@
};
exports.Base = (function() {
Base = (function() {
return function Base() {
function Base() {
this.tags = {};
return this;
};
return Base;
})();
Base.prototype.compile = function(o) {
var closure, code, top;
@ -141,9 +142,12 @@
if (func(child) === false) {
return false;
}
return child instanceof Base && (crossScope || !(child instanceof Code)) ? child.traverseChildren(crossScope, func) : undefined;
return crossScope || !(child instanceof Code) ? child.traverseChildren(crossScope, func) : undefined;
});
};
Base.prototype.invert = function() {
return new Op('!', this);
};
Base.prototype.children = [];
Base.prototype.unwrap = THIS;
Base.prototype.isStatement = NO;
@ -154,11 +158,12 @@
})();
exports.Expressions = (function() {
Expressions = (function() {
return function Expressions(nodes) {
function Expressions(nodes) {
Expressions.__super__.constructor.call(this);
this.expressions = compact(flatten(nodes || []));
return this;
};
return Expressions;
})();
__extends(Expressions, Base);
Expressions.prototype.children = ['expressions'];
@ -204,12 +209,13 @@
}).call(this).join("\n");
};
Expressions.prototype.compileRoot = function(o) {
var code;
o.indent = (this.tab = o.noWrap ? '' : TAB);
var code, wrap;
wrap = (o.wrap != null) ? o.wrap : true;
o.indent = (this.tab = wrap ? TAB : '');
o.scope = new Scope(null, this, null);
code = this.compileWithDeclarations(o);
code = code.replace(TRAILING_WHITESPACE, '');
return o.noWrap ? code : ("(function() {\n" + code + "\n}).call(this);\n");
return wrap ? ("(function() {\n" + code + "\n}).call(this);\n") : code;
};
Expressions.prototype.compileWithDeclarations = function(o) {
var code;
@ -240,11 +246,12 @@
};
exports.Literal = (function() {
Literal = (function() {
return function Literal(_arg) {
function Literal(_arg) {
this.value = _arg;
Literal.__super__.constructor.call(this);
return this;
};
return Literal;
})();
__extends(Literal, Base);
Literal.prototype.makeReturn = function() {
@ -273,11 +280,12 @@
})();
exports.Return = (function() {
Return = (function() {
return function Return(_arg) {
function Return(_arg) {
this.expression = _arg;
Return.__super__.constructor.call(this);
return this;
};
return Return;
})();
__extends(Return, Base);
Return.prototype.isStatement = YES;
@ -307,7 +315,7 @@
})();
exports.Value = (function() {
Value = (function() {
return function Value(_arg, _arg2, tag) {
function Value(_arg, _arg2, tag) {
this.properties = _arg2;
this.base = _arg;
Value.__super__.constructor.call(this);
@ -317,6 +325,7 @@
}
return this;
};
return Value;
})();
__extends(Value, Base);
Value.prototype.children = ['base', 'properties'];
@ -439,11 +448,12 @@
}).call(this);
exports.Comment = (function() {
Comment = (function() {
return function Comment(_arg) {
function Comment(_arg) {
this.comment = _arg;
Comment.__super__.constructor.call(this);
return this;
};
return Comment;
})();
__extends(Comment, Base);
Comment.prototype.isStatement = YES;
@ -455,7 +465,7 @@
})();
exports.Call = (function() {
Call = (function() {
return function Call(variable, _arg, _arg2) {
function Call(variable, _arg, _arg2) {
this.exist = _arg2;
this.args = _arg;
Call.__super__.constructor.call(this);
@ -465,6 +475,7 @@
this.args || (this.args = []);
return this;
};
return Call;
})();
__extends(Call, Base);
Call.prototype.children = ['variable', 'args'];
@ -602,12 +613,13 @@
})();
exports.Extends = (function() {
Extends = (function() {
return function Extends(_arg, _arg2) {
function Extends(_arg, _arg2) {
this.parent = _arg2;
this.child = _arg;
Extends.__super__.constructor.call(this);
return this;
};
return Extends;
})();
__extends(Extends, Base);
Extends.prototype.children = ['child', 'parent'];
@ -620,13 +632,14 @@
})();
exports.Accessor = (function() {
Accessor = (function() {
return function Accessor(_arg, tag) {
function Accessor(_arg, tag) {
this.name = _arg;
Accessor.__super__.constructor.call(this);
this.prototype = tag === 'prototype' ? '.prototype' : '';
this.soakNode = tag === 'soak';
return this;
};
return Accessor;
})();
__extends(Accessor, Base);
Accessor.prototype.children = ['name'];
@ -641,11 +654,12 @@
})();
exports.Index = (function() {
Index = (function() {
return function Index(_arg) {
function Index(_arg) {
this.index = _arg;
Index.__super__.constructor.call(this);
return this;
};
return Index;
})();
__extends(Index, Base);
Index.prototype.children = ['index'];
@ -662,7 +676,7 @@
})();
exports.Range = (function() {
Range = (function() {
return function Range(_arg, _arg2, tag) {
function Range(_arg, _arg2, tag) {
this.to = _arg2;
this.from = _arg;
Range.__super__.constructor.call(this);
@ -670,6 +684,7 @@
this.equals = this.exclusive ? '' : '=';
return this;
};
return Range;
})();
__extends(Range, Base);
Range.prototype.children = ['from', 'to'];
@ -749,11 +764,12 @@
})();
exports.Slice = (function() {
Slice = (function() {
return function Slice(_arg) {
function Slice(_arg) {
this.range = _arg;
Slice.__super__.constructor.call(this);
return this;
};
return Slice;
})();
__extends(Slice, Base);
Slice.prototype.children = ['range'];
@ -771,11 +787,12 @@
})();
exports.ObjectLiteral = (function() {
ObjectLiteral = (function() {
return function ObjectLiteral(props) {
function ObjectLiteral(props) {
ObjectLiteral.__super__.constructor.call(this);
this.objects = (this.properties = props || []);
return this;
};
return ObjectLiteral;
})();
__extends(ObjectLiteral, Base);
ObjectLiteral.prototype.children = ['properties'];
@ -826,12 +843,13 @@
})();
exports.ArrayLiteral = (function() {
ArrayLiteral = (function() {
return function ArrayLiteral(_arg) {
function ArrayLiteral(_arg) {
this.objects = _arg;
ArrayLiteral.__super__.constructor.call(this);
this.objects || (this.objects = []);
return this;
};
return ArrayLiteral;
})();
__extends(ArrayLiteral, Base);
ArrayLiteral.prototype.children = ['objects'];
@ -839,30 +857,28 @@
return Splat.compileSplattedArray(this.objects, o);
};
ArrayLiteral.prototype.compileNode = function(o) {
var _len, _ref2, code, i, obj, objects;
var _i, _len, _len2, _ref2, _ref3, code, i, obj, objects;
o.indent = this.idt(1);
objects = [];
for (i = 0, _len = (_ref2 = this.objects).length; i < _len; i++) {
obj = _ref2[i];
code = obj.compile(o);
for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; _i++) {
obj = _ref2[_i];
if (obj instanceof Splat) {
return this.compileSplatLiteral(o);
} else if (obj instanceof Comment) {
objects.push("\n" + code + "\n" + (o.indent));
} else if (i === this.objects.length - 1) {
objects.push(code);
} else {
objects.push("" + code + ", ");
}
}
objects = [];
for (i = 0, _len2 = (_ref3 = this.objects).length; i < _len2; i++) {
obj = _ref3[i];
code = obj.compile(o);
objects.push(obj instanceof Comment ? ("\n" + code + "\n" + (o.indent)) : (i === this.objects.length - 1 ? code : code + ', '));
}
objects = objects.join('');
return indexOf(objects, '\n') >= 0 ? ("[\n" + (this.idt(1)) + objects + "\n" + (this.tab) + "]") : ("[" + objects + "]");
return 0 < objects.indexOf('\n') ? ("[\n" + (o.indent) + objects + "\n" + (this.tab) + "]") : ("[" + objects + "]");
};
return ArrayLiteral;
})();
exports.Class = (function() {
Class = (function() {
return function Class(variable, _arg, _arg2) {
function Class(variable, _arg, _arg2) {
this.properties = _arg2;
this.parent = _arg;
Class.__super__.constructor.call(this);
@ -871,6 +887,7 @@
this.returns = false;
return this;
};
return Class;
})();
__extends(Class, Base);
Class.prototype.children = ['variable', 'parent', 'properties'];
@ -915,7 +932,7 @@
func.name = className;
func.body.push(new Return(new Literal('this')));
variable = new Value(variable);
variable.namespaced = include(func.name, '.');
variable.namespaced = 0 < className.indexOf('.');
constructor = func;
continue;
}
@ -956,13 +973,14 @@
})();
exports.Assign = (function() {
Assign = (function() {
return function Assign(_arg, _arg2, _arg3) {
function Assign(_arg, _arg2, _arg3) {
this.context = _arg3;
this.value = _arg2;
this.variable = _arg;
Assign.__super__.constructor.call(this);
return this;
};
return Assign;
})();
__extends(Assign, Base);
Assign.prototype.METHOD_DEF = /^(?:(\S+)\.prototype\.)?([$A-Za-z_][$\w]*)$/;
@ -972,7 +990,7 @@
return this.variable instanceof Value;
};
Assign.prototype.compileNode = function(o) {
var isValue, match, name, node, stmt, top, val;
var ifn, isValue, match, name, stmt, top, val;
if (isValue = this.isValue()) {
if (this.variable.isArray() || this.variable.isObject()) {
return this.compilePatternMatch(o);
@ -980,8 +998,9 @@
if (this.variable.isSplice()) {
return this.compileSplice(o);
}
if (node = Value.unfoldSoak(o, this, 'variable')) {
return node.compile(o);
if (ifn = Value.unfoldSoak(o, this, 'variable')) {
delete o.top;
return ifn.compile(o);
}
}
top = del(o, 'top');
@ -1080,7 +1099,7 @@
})();
exports.Code = (function() {
Code = (function() {
return function Code(_arg, _arg2, tag) {
function Code(_arg, _arg2, tag) {
this.body = _arg2;
this.params = _arg;
Code.__super__.constructor.call(this);
@ -1092,6 +1111,7 @@
}
return this;
};
return Code;
})();
__extends(Code, Base);
Code.prototype.children = ['params', 'body'];
@ -1103,7 +1123,7 @@
o.top = true;
o.indent = this.idt(1);
empty = this.body.expressions.length === 0;
del(o, 'noWrap');
del(o, 'wrap');
del(o, 'globals');
splat = undefined;
params = [];
@ -1152,8 +1172,8 @@
o.indent = this.idt(2);
}
code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : '';
open = this.className ? ("(function() {\n" + (this.idt(1)) + "return function " + (this.className) + "(") : "function(";
close = this.className ? ("" + (code && this.idt(1)) + "};\n" + (this.tab) + "})()") : ("" + (code && this.tab) + "}");
open = this.className ? ("(function() {\n" + (this.idt(1)) + "function " + (this.className) + "(") : "function(";
close = this.className ? ("" + (code && this.idt(1)) + "};\n" + (this.idt(1)) + "return " + (this.className) + ";\n" + (this.tab) + "})()") : ("" + (code && this.tab) + "}");
func = ("" + open + (params.join(', ')) + ") {" + code + close);
o.scope.endLevel();
if (this.bound) {
@ -1169,7 +1189,7 @@
})();
exports.Param = (function() {
Param = (function() {
return function Param(_arg, _arg2, _arg3) {
function Param(_arg, _arg2, _arg3) {
this.splat = _arg3;
this.attach = _arg2;
this.name = _arg;
@ -1177,6 +1197,7 @@
this.value = new Literal(this.name);
return this;
};
return Param;
})();
__extends(Param, Base);
Param.prototype.children = ['name'];
@ -1198,7 +1219,7 @@
})();
exports.Splat = (function() {
Splat = (function() {
return function Splat(name) {
function Splat(name) {
Splat.__super__.constructor.call(this);
if (!name.compile) {
name = new Literal(name);
@ -1206,6 +1227,7 @@
this.name = name;
return this;
};
return Splat;
})();
__extends(Splat, Base);
Splat.prototype.children = ['name'];
@ -1268,18 +1290,13 @@
}).call(this);
exports.While = (function() {
While = (function() {
return function While(condition, opts) {
function While(condition, opts) {
While.__super__.constructor.call(this);
if (((opts != null) ? opts.invert : undefined)) {
if (condition instanceof Op) {
condition = new Parens(condition);
}
condition = new Op('!', condition);
}
this.condition = condition;
this.condition = ((opts != null) ? opts.invert : undefined) ? condition.invert() : condition;
this.guard = ((opts != null) ? opts.guard : undefined);
return this;
};
return While;
})();
__extends(While, Base);
While.prototype.children = ['condition', 'guard', 'body'];
@ -1297,9 +1314,9 @@
var cond, post, pre, rvar, set, top;
top = del(o, 'top') && !this.returns;
o.indent = this.idt(1);
o.top = true;
this.condition.parenthetical = true;
cond = this.condition.compile(o);
o.top = true;
set = '';
if (!top) {
rvar = o.scope.freeVariable('result');
@ -1325,7 +1342,7 @@
})();
exports.Op = (function() {
Op = (function() {
return function Op(_arg, _arg2, _arg3, flip) {
function Op(_arg, _arg2, _arg3, flip) {
this.second = _arg3;
this.first = _arg2;
this.operator = _arg;
@ -1343,6 +1360,7 @@
}
return this;
};
return Op;
})();
__extends(Op, Base);
Op.prototype.CONVERSIONS = {
@ -1361,10 +1379,6 @@
Op.prototype.isUnary = function() {
return !this.second;
};
Op.prototype.isInvertible = function() {
var _ref2;
return ('===' === (_ref2 = this.operator) || '!==' === _ref2);
};
Op.prototype.isComplex = function() {
return this.operator !== '!' || this.first.isComplex();
};
@ -1376,7 +1390,11 @@
return include(this.CHAINABLE, this.operator);
};
Op.prototype.invert = function() {
return (this.operator = this.INVERSIONS[this.operator]);
var _ref2;
if (('===' === (_ref2 = this.operator) || '!==' === _ref2)) {
this.operator = this.INVERSIONS[this.operator];
return this;
} else return this.second ? new Parens(this).invert() : Op.__super__.invert.call(this);
};
Op.prototype.toString = function(idt) {
return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator);
@ -1385,7 +1403,7 @@
if (this.isChainable() && this.first.unwrap() instanceof Op && this.first.unwrap().isChainable()) {
return this.compileChain(o);
}
if (indexOf(this.ASSIGNMENT, this.operator) >= 0) {
if (include(this.ASSIGNMENT, this.operator)) {
return this.compileAssignment(o);
}
if (this.isUnary()) {
@ -1428,23 +1446,21 @@
};
Op.prototype.compileUnary = function(o) {
var parts, space;
space = indexOf(this.PREFIX_OPERATORS, this.operator) >= 0 ? ' ' : '';
space = include(this.PREFIX_OPERATORS, this.operator) ? ' ' : '';
parts = [this.operator, space, this.first.compile(o)];
if (this.flip) {
parts = parts.reverse();
}
return parts.join('');
return (this.flip ? parts.reverse() : parts).join('');
};
return Op;
})();
exports.In = (function() {
In = (function() {
return function In(_arg, _arg2) {
function In(_arg, _arg2) {
this.array = _arg2;
this.object = _arg;
In.__super__.constructor.call(this);
return this;
};
return In;
})();
__extends(In, Base);
In.prototype.children = ['object', 'array'];
@ -1483,7 +1499,7 @@
})();
exports.Try = (function() {
Try = (function() {
return function Try(_arg, _arg2, _arg3, _arg4) {
function Try(_arg, _arg2, _arg3, _arg4) {
this.ensure = _arg4;
this.recovery = _arg3;
this.error = _arg2;
@ -1491,6 +1507,7 @@
Try.__super__.constructor.call(this);
return this;
};
return Try;
})();
__extends(Try, Base);
Try.prototype.children = ['attempt', 'recovery', 'ensure'];
@ -1518,11 +1535,12 @@
})();
exports.Throw = (function() {
Throw = (function() {
return function Throw(_arg) {
function Throw(_arg) {
this.expression = _arg;
Throw.__super__.constructor.call(this);
return this;
};
return Throw;
})();
__extends(Throw, Base);
Throw.prototype.children = ['expression'];
@ -1535,11 +1553,12 @@
})();
exports.Existence = (function() {
Existence = (function() {
return function Existence(_arg) {
function Existence(_arg) {
this.expression = _arg;
Existence.__super__.constructor.call(this);
return this;
};
return Existence;
})();
__extends(Existence, Base);
Existence.prototype.children = ['expression'];
@ -1553,11 +1572,12 @@
})();
exports.Parens = (function() {
Parens = (function() {
return function Parens(_arg) {
function Parens(_arg) {
this.expression = _arg;
Parens.__super__.constructor.call(this);
return this;
};
return Parens;
})();
__extends(Parens, Base);
Parens.prototype.children = ['expression'];
@ -1588,7 +1608,7 @@
})();
exports.For = (function() {
For = (function() {
return function For(_arg, source, _arg2, _arg3) {
function For(_arg, source, _arg2, _arg3) {
var _ref2, _ref3;
this.index = _arg3;
this.name = _arg2;
@ -1607,6 +1627,7 @@
this.returns = false;
return this;
};
return For;
})();
__extends(For, Base);
For.prototype.children = ['body', 'source', 'guard'];
@ -1723,7 +1744,7 @@
})();
exports.Switch = (function() {
Switch = (function() {
return function Switch(_arg, _arg2, _arg3) {
function Switch(_arg, _arg2, _arg3) {
this.otherwise = _arg3;
this.cases = _arg2;
this.subject = _arg;
@ -1732,6 +1753,7 @@
this.subject || (this.subject = new Literal('true'));
return this;
};
return Switch;
})();
__extends(Switch, Base);
Switch.prototype.children = ['subject', 'cases', 'otherwise'];
@ -1778,27 +1800,16 @@
})();
exports.If = (function() {
If = (function() {
return function If(condition, _arg, _arg2) {
var op;
function If(condition, _arg, _arg2) {
this.tags = _arg2;
this.body = _arg;
this.tags || (this.tags = {});
if (this.tags.invert) {
op = condition instanceof Op;
if (op && condition.isInvertible()) {
condition.invert();
} else {
if (op && !condition.isUnary()) {
condition = new Parens(condition);
}
condition = new Op('!', condition);
}
}
this.condition = condition;
this.condition = this.tags.invert ? condition.invert() : condition;
this.elseBody = null;
this.isChain = false;
return this;
};
return If;
})();
__extends(If, Base);
If.prototype.children = ['condition', 'body', 'elseBody', 'assigner'];
@ -1811,9 +1822,9 @@
var _ref2;
return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined);
};
If.prototype.addElse = function(elseBody, statement) {
If.prototype.addElse = function(elseBody) {
if (this.isChain) {
this.elseBodyNode().addElse(elseBody, statement);
this.elseBodyNode().addElse(elseBody);
} else {
this.isChain = elseBody instanceof If;
this.elseBody = this.ensureExpressions(elseBody);
@ -1821,22 +1832,12 @@
return this;
};
If.prototype.isStatement = function(o) {
return this.statement || (this.statement = !!((o && o.top) || this.bodyNode().isStatement(o) || (this.elseBody && this.elseBodyNode().isStatement(o))));
var _ref2;
return this.statement || (this.statement = ((o != null) ? o.top : undefined) || this.bodyNode().isStatement(o) || (((_ref2 = this.elseBodyNode()) != null) ? _ref2.isStatement(o) : undefined));
};
If.prototype.compileCondition = function(o) {
var _i, _len, _result, cond, conditions;
conditions = flatten([this.condition]);
if (conditions.length === 1) {
conditions[0].parenthetical = true;
}
return (function() {
_result = [];
for (_i = 0, _len = conditions.length; _i < _len; _i++) {
cond = conditions[_i];
_result.push(cond.compile(o));
}
return _result;
})().join(' || ');
this.condition.parenthetical = true;
return this.condition.compile(o);
};
If.prototype.compileNode = function(o) {
return this.isStatement(o) ? this.compileStatement(o) : this.compileExpression(o);
@ -1854,24 +1855,23 @@
return node instanceof Expressions ? node : new Expressions([node]);
};
If.prototype.compileStatement = function(o) {
var body, child, comDent, condO, elsePart, ifDent, ifPart, top;
var child, condO, ifPart, top;
top = del(o, 'top');
child = del(o, 'chainChild');
condO = merge(o);
o.indent = this.idt(1);
o.top = true;
ifDent = child || (top && !this.isStatement(o)) ? '' : this.idt();
comDent = child ? this.idt() : '';
body = this.body.compile(o);
ifPart = ("" + ifDent + "if (" + (this.compileCondition(condO)) + ") {\n" + body + "\n" + (this.tab) + "}");
ifPart = ("if (" + (this.compileCondition(condO)) + ") {\n" + (this.body.compile(o)) + "\n" + (this.tab) + "}");
if (!child) {
ifPart = this.tab + ifPart;
}
if (!this.elseBody) {
return ifPart;
}
elsePart = this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, {
indent: this.idt(),
return ifPart + (this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, {
indent: this.tab,
chainChild: true
})) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}");
return "" + ifPart + elsePart;
})) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}"));
};
If.prototype.compileExpression = function(o) {
var code, elsePart, ifPart;

View File

@ -2,11 +2,12 @@
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
exports.OptionParser = (function() {
OptionParser = (function() {
return function OptionParser(rules, banner) {
function OptionParser(rules, banner) {
this.banner = banner;
this.rules = buildRules(rules);
return this;
};
return OptionParser;
})();
OptionParser.prototype.parse = function(args) {
var _i, _len, _len2, _ref, arg, i, isOption, matchedRule, options, rule, value;

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,7 @@
var val;
try {
val = CoffeeScript.eval(buffer.toString(), {
noWrap: true,
wrap: false,
globals: true,
fileName: 'repl'
});

View File

@ -2,7 +2,8 @@
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, _i, _len, _ref, include, left, rite;
include = require('./helpers').include;
exports.Rewriter = (function() {
return function Rewriter() {};
function Rewriter() {};
return Rewriter;
})();
exports.Rewriter.prototype.rewrite = function(_arg) {
this.tokens = _arg;
@ -365,7 +366,7 @@
}
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY', 'TRUE', 'FALSE', '@', '->', '=>', '[', '(', '{'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', '@', '->', '=>', '[', '(', '{'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];

View File

@ -4,7 +4,7 @@
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
exports.Scope = (function() {
Scope = (function() {
return function Scope(_arg, _arg2, _arg3) {
function Scope(_arg, _arg2, _arg3) {
this.method = _arg3;
this.expressions = _arg2;
this.parent = _arg;
@ -19,6 +19,7 @@
}
return this;
};
return Scope;
})();
Scope.root = null;
Scope.prototype.startLevel = function() {

View File

@ -185,7 +185,7 @@ parseOptions = ->
# The compile-time options to pass to the CoffeeScript compiler.
compileOptions = (fileName) ->
o = {fileName}
o.noWrap = opts['no-wrap']
o.wrap = !opts['no-wrap']
o
# Print the `--help` usage message and exit.

View File

@ -130,9 +130,7 @@ grammar =
o "AlphaNumeric"
o "JS", -> new Literal $1
o "REGEX", -> new Literal $1
o "TRUE", -> new Literal true
o "FALSE", -> new Literal false
o "NULL", -> new Literal 'null'
o "BOOL", -> new Literal $1
]
# Assignment of a variable, property, or index to a value.
@ -195,7 +193,7 @@ grammar =
ParamList: [
o "", -> []
o "Param", -> [$1]
o "ParamList , Param", -> $1.concat [$3]
o "ParamList , Param", -> $1.concat $3
]
# A single parameter in a function definition can be ordinary, or a splat
@ -265,8 +263,8 @@ grammar =
AssignList: [
o "", -> []
o "AssignObj", -> [$1]
o "AssignList , AssignObj", -> $1.concat [$3]
o "AssignList OptComma TERMINATOR AssignObj", -> $1.concat [$4]
o "AssignList , AssignObj", -> $1.concat $3
o "AssignList OptComma TERMINATOR AssignObj", -> $1.concat $4
o "AssignList OptComma INDENT AssignList OptComma OUTDENT", -> $1.concat $4
]
@ -363,8 +361,8 @@ grammar =
# (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o "Arg", -> [$1]
o "ArgList , Arg", -> $1.concat [$3]
o "ArgList OptComma TERMINATOR Arg", -> $1.concat [$4]
o "ArgList , Arg", -> $1.concat $3
o "ArgList OptComma TERMINATOR Arg", -> $1.concat $4
o "INDENT ArgList OptComma OUTDENT", -> $2
o "ArgList OptComma INDENT ArgList OptComma OUTDENT", -> $1.concat $4
]
@ -380,8 +378,7 @@ grammar =
# having the newlines wouldn't make sense.
SimpleArgs: [
o "Expression"
o "SimpleArgs , Expression", ->
if $1 instanceof Array then $1.concat([$3]) else [$1].concat([$3])
o "SimpleArgs , Expression", -> [].concat $1, $3
]
# The variants of *try/catch/finally* exception handling blocks.
@ -527,8 +524,8 @@ grammar =
# rules are necessary.
Operation: [
o "UNARY Expression", -> new Op $1, $2
o("- Expression", (-> new Op('-', $2)), {prec: 'UNARY'})
o("+ Expression", (-> new Op('+', $2)), {prec: 'UNARY'})
o "- Expression", (-> new Op '-', $2), prec: 'UNARY'
o "+ Expression", (-> new Op '+', $2), prec: 'UNARY'
o "-- Expression", -> new Op '--', $2
o "++ Expression", -> new Op '++', $2

View File

@ -73,12 +73,12 @@ exports.Lexer = class Lexer
# though `is` means `===` otherwise.
identifierToken: ->
return false unless match = IDENTIFIER.exec @chunk
id = match[0]
@i += id.length
[input, id, colon] = match
@i += input.length
if id is 'all' and @tag() is 'FOR'
@token 'ALL', id
return true
forcedIdentifier = @tagAccessor() or ASSIGNED.test @chunk
forcedIdentifier = colon or @tagAccessor()
tag = 'IDENTIFIER'
if include(JS_KEYWORDS, id) or
not forcedIdentifier and include(COFFEE_KEYWORDS, id)
@ -103,7 +103,7 @@ exports.Lexer = class Lexer
tag = 'IDENTIFIER'
id = new String id
id.reserved = yes
else if include(RESERVED, id)
else if include RESERVED, id
@identifierError id
unless forcedIdentifier
tag = id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
@ -111,7 +111,11 @@ exports.Lexer = class Lexer
tag = 'UNARY'
else if include LOGIC, id
tag = 'LOGIC'
else if include BOOL, tag
id = tag.toLowerCase()
tag = 'BOOL'
@token tag, id
@token ':', ':' if colon
true
# Matches numbers, including decimals, hex, and exponential notation.
@ -311,9 +315,9 @@ exports.Lexer = class Lexer
prev = last @tokens
if value is '='
@assignmentError() if not prev[1].reserved and include JS_FORBIDDEN, prev[1]
if prev[1] in ['or', 'and']
if prev[1] in ['||', '&&']
prev[0] = 'COMPOUND_ASSIGN'
prev[1] = COFFEE_ALIASES[prev[1]] + '='
prev[1] += '='
return true
if ';' is value then tag = 'TERMINATOR'
else if include LOGIC , value then tag = 'LOGIC'
@ -343,17 +347,17 @@ exports.Lexer = class Lexer
# is the previous token.
tagAccessor: ->
return false if not (prev = last @tokens) or prev.spaced
accessor = if prev[1] is '::'
if prev[1] is '::'
@tag 0, 'PROTOTYPE_ACCESS'
else if prev[1] is '.' and @value(1) isnt '.'
if @tag(1) is '?'
@tag(0, 'SOAK_ACCESS')
@tag 0, 'SOAK_ACCESS'
@tokens.splice(-2, 1)
else
@tag 0, 'PROPERTY_ACCESS'
else
prev[0] is '@'
if accessor then 'accessor' else false
return prev[0] is '@'
true
# Sanitize a heredoc or herecomment by
# erasing all external indentation on the left-hand side.
@ -374,12 +378,11 @@ exports.Lexer = class Lexer
tagParameters: ->
return if @tag() isnt ')'
i = @tokens.length
loop
return unless tok = @tokens[--i]
while tok = @tokens[--i]
switch tok[0]
when 'IDENTIFIER' then tok[0] = 'PARAM'
when ')' then tok[0] = 'PARAM_END'
when '(', 'CALL_START' then return tok[0] = 'PARAM_START'
when '(', 'CALL_START' then tok[0] = 'PARAM_START'; return true
true
# Close up all remaining open blocks at the end of the file.
@ -389,12 +392,12 @@ exports.Lexer = class Lexer
# The error for when you try to use a forbidden word in JavaScript as
# an identifier.
identifierError: (word) ->
throw new Error "SyntaxError: Reserved word \"#{word}\" on line #{@line + 1}"
throw SyntaxError "Reserved word \"#{word}\" on line #{@line + 1}"
# The error for when you try to assign to a reserved word in JavaScript,
# like "function" or "default".
assignmentError: ->
throw new Error "SyntaxError: Reserved word \"#{@value()}\" on line #{@line + 1} can't be assigned"
throw SyntaxError "Reserved word \"#{@value()}\" on line #{@line + 1} can't be assigned"
# Matches a balanced group such as a single or double-quoted string. Pass in
# a series of delimiters, all of which must be nested correctly within the
@ -545,7 +548,10 @@ RESERVED = [
JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
# Token matching regexes.
IDENTIFIER = /^[a-zA-Z_$][\w$]*/
IDENTIFIER = /// ^
( [$A-Za-z_][$\w]* )
( [^\n\S]* : (?!:) )? # Is this a property name?
///
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/
OPERATOR = /// ^ (?: -[-=>]? | \+[+=]? | \.\.\.? | [*&|/%=<>^:!?]+ ) ///
@ -606,13 +612,16 @@ MATH = ['*', '/', '%']
# Relational tokens that are negatable with `not` prefix.
RELATION = ['IN', 'OF', 'INSTANCEOF']
# Boolean tokens.
BOOL = ['TRUE', 'FALSE', 'NULL']
# Tokens which a regular expression will never immediately follow, but which
# a division operator might.
#
# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
#
# Our list is shorter, due to sans-parentheses method calls.
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']']
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']
# Tokens which could legitimately be invoked or indexed. A opening
# parentheses or bracket following these tokens will be recorded as the start

View File

@ -6,7 +6,7 @@
{Scope} = require './scope'
# Import the helpers we plan to use.
{compact, flatten, merge, del, include, indexOf, starts, ends, last} = require './helpers'
{compact, flatten, merge, del, include, starts, ends, last} = require './helpers'
# Constant functions for nodes that don't need customization.
YES = -> yes
@ -128,10 +128,11 @@ exports.Base = class Base
traverseChildren: (crossScope, func) ->
@eachChild (child) ->
return false if func(child) is false
if child instanceof Base and
(crossScope or child not instanceof Code)
if crossScope or child not instanceof Code
child.traverseChildren crossScope, func
invert: -> new Op '!', this
# Default implementations of the common node properties and methods. Nodes
# will override these with custom logic, if needed.
children: []
@ -197,24 +198,21 @@ exports.Expressions = class Expressions extends Base
# It would be better not to generate them in the first place, but for now,
# clean up obvious double-parentheses.
compileRoot: (o) ->
o.indent = @tab = if o.noWrap then '' else TAB
wrap = if o.wrap? then o.wrap else true
o.indent = @tab = if wrap then TAB else ''
o.scope = new Scope(null, this, null)
code = @compileWithDeclarations(o)
code = code.replace(TRAILING_WHITESPACE, '')
if o.noWrap then code else "(function() {\n#{code}\n}).call(this);\n"
if wrap then "(function() {\n#{code}\n}).call(this);\n" else code
# Compile the expressions body for the contents of a function, with
# declarations of all inner variables pushed up to the top.
compileWithDeclarations: (o) ->
code = @compileNode(o)
code = """
#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };
#{code}
""" if o.scope.hasAssignments this
code = """
#{@tab}var #{o.scope.compiledDeclarations()};
#{code}
""" if not o.globals and o.scope.hasDeclarations this
if o.scope.hasAssignments this
code = "#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };\n#{code}"
if not o.globals and o.scope.hasDeclarations this
code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#{code}"
code
# Compiles a single expression within the expressions body. If we need to
@ -736,20 +734,21 @@ exports.ArrayLiteral = class ArrayLiteral extends Base
compileNode: (o) ->
o.indent = @idt 1
for obj in @objects when obj instanceof Splat
return @compileSplatLiteral o
objects = []
for obj, i in @objects
code = obj.compile(o)
if obj instanceof Splat
return @compileSplatLiteral o
else if obj instanceof Comment
objects.push "\n#{code}\n#{o.indent}"
code = obj.compile o
objects.push (if obj instanceof Comment
"\n#{code}\n#{o.indent}"
else if i is @objects.length - 1
objects.push code
code
else
objects.push "#{code}, "
objects = objects.join('')
if indexOf(objects, '\n') >= 0
"[\n#{@idt(1)}#{objects}\n#{@tab}]"
code + ', '
)
objects = objects.join ''
if 0 < objects.indexOf '\n'
"[\n#{o.indent}#{objects}\n#{@tab}]"
else
"[#{objects}]"
@ -806,7 +805,7 @@ exports.Class = class Class extends Base
func.name = className
func.body.push new Return new Literal 'this'
variable = new Value variable
variable.namespaced = include func.name, '.'
variable.namespaced = 0 < className.indexOf '.'
constructor = func
continue
if func instanceof Code and func.bound
@ -860,7 +859,9 @@ exports.Assign = class Assign extends Base
if isValue = @isValue()
return @compilePatternMatch(o) if @variable.isArray() or @variable.isObject()
return @compileSplice(o) if @variable.isSplice()
return node.compile o if node = Value.unfoldSoak o, this, 'variable'
if ifn = Value.unfoldSoak o, this, 'variable'
delete o.top
return ifn.compile o
top = del o, 'top'
stmt = del o, 'asStatement'
name = @variable.compile(o)
@ -964,7 +965,7 @@ exports.Code = class Code extends Base
o.top = true
o.indent = @idt(1)
empty = @body.expressions.length is 0
del o, 'noWrap'
del o, 'wrap'
del o, 'globals'
splat = undefined
params = []
@ -993,8 +994,8 @@ exports.Code = class Code extends Base
(o.scope.parameter(param)) for param in params
o.indent = @idt 2 if @className
code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else ''
open = if @className then "(function() {\n#{@idt(1)}return function #{@className}(" else "function("
close = if @className then "#{code and @idt(1)}};\n#{@tab}})()" else "#{code and @tab}}"
open = if @className then "(function() {\n#{@idt(1)}function #{@className}(" else "function("
close = if @className then "#{code and @idt(1)}};\n#{@idt(1)}return #{@className};\n#{@tab}})()" else "#{code and @tab}}"
func = "#{open}#{ params.join(', ') }) {#{code}#{close}"
o.scope.endLevel()
return "#{utility 'bind'}(#{func}, #{@context})" if @bound
@ -1102,10 +1103,7 @@ exports.While = class While extends Base
constructor: (condition, opts) ->
super()
if opts?.invert
condition = new Parens condition if condition instanceof Op
condition = new Op('!', condition)
@condition = condition
@condition = if opts?.invert then condition.invert() else condition
@guard = opts?.guard
addBody: (body) ->
@ -1124,9 +1122,9 @@ exports.While = class While extends Base
compileNode: (o) ->
top = del(o, 'top') and not @returns
o.indent = @idt 1
o.top = true
@condition.parenthetical = yes
cond = @condition.compile(o)
o.top = true
set = ''
unless top
rvar = o.scope.freeVariable 'result'
@ -1183,9 +1181,6 @@ exports.Op = class Op extends Base
isUnary: ->
not @second
isInvertible: ->
@operator in ['===', '!==']
isComplex: -> @operator isnt '!' or @first.isComplex()
isMutator: ->
@ -1195,14 +1190,20 @@ exports.Op = class Op extends Base
include(@CHAINABLE, @operator)
invert: ->
@operator = @INVERSIONS[@operator]
if @operator in ['===', '!==']
@operator = @INVERSIONS[@operator]
this
else if @second
new Parens(this).invert()
else
super()
toString: (idt) ->
super(idt, @constructor.name + ' ' + @operator)
compileNode: (o) ->
return @compileChain(o) if @isChainable() and @first.unwrap() instanceof Op and @first.unwrap().isChainable()
return @compileAssignment(o) if indexOf(@ASSIGNMENT, @operator) >= 0
return @compileAssignment(o) if include @ASSIGNMENT, @operator
return @compileUnary(o) if @isUnary()
return @compileExistence(o) if @operator is '?'
@first = new Parens @first if @first instanceof Op and @first.isMutator()
@ -1239,10 +1240,9 @@ exports.Op = class Op extends Base
# Compile a unary **Op**.
compileUnary: (o) ->
space = if indexOf(@PREFIX_OPERATORS, @operator) >= 0 then ' ' else ''
space = if include @PREFIX_OPERATORS, @operator then ' ' else ''
parts = [@operator, space, @first.compile(o)]
parts = parts.reverse() if @flip
parts.join('')
(if @flip then parts.reverse() else parts).join ''
#### In
exports.In = class In extends Base
@ -1516,14 +1516,7 @@ exports.If = class If extends Base
constructor: (condition, @body, @tags) ->
@tags or= {}
if @tags.invert
op = condition instanceof Op
if op and condition.isInvertible()
condition.invert()
else
condition = new Parens condition if op and not condition.isUnary()
condition = new Op '!', condition
@condition = condition
@condition = if @tags.invert then condition.invert() else condition
@elseBody = null
@isChain = false
@ -1531,23 +1524,22 @@ exports.If = class If extends Base
elseBodyNode: -> @elseBody?.unwrap()
# Rewrite a chain of **Ifs** to add a default case as the final *else*.
addElse: (elseBody, statement) ->
addElse: (elseBody) ->
if @isChain
@elseBodyNode().addElse elseBody, statement
@elseBodyNode().addElse elseBody
else
@isChain = elseBody instanceof If
@isChain = elseBody instanceof If
@elseBody = @ensureExpressions elseBody
this
# The **If** only compiles into a statement if either of its bodies needs
# to be a statement. Otherwise a conditional operator is safe.
isStatement: (o) ->
@statement or= !!((o and o.top) or @bodyNode().isStatement(o) or (@elseBody and @elseBodyNode().isStatement(o)))
@statement or= o?.top or @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
compileCondition: (o) ->
conditions = flatten [@condition]
conditions[0].parenthetical = yes if conditions.length is 1
(cond.compile(o) for cond in conditions).join(' || ')
@condition.parenthetical = yes
@condition.compile o
compileNode: (o) ->
if @isStatement o then @compileStatement o else @compileExpression o
@ -1571,16 +1563,13 @@ exports.If = class If extends Base
condO = merge o
o.indent = @idt 1
o.top = true
ifDent = if child or (top and not @isStatement(o)) then '' else @idt()
comDent = if child then @idt() else ''
body = @body.compile(o)
ifPart = "#{ifDent}if (#{ @compileCondition(condO) }) {\n#{body}\n#{@tab}}"
ifPart = "if (#{ @compileCondition condO }) {\n#{ @body.compile o }\n#{@tab}}"
ifPart = @tab + ifPart unless child
return ifPart unless @elseBody
elsePart = if @isChain
' else ' + @elseBodyNode().compile(merge(o, {indent: @idt(), chainChild: true}))
ifPart + if @isChain
' else ' + @elseBodyNode().compile merge o, indent: @tab, chainChild: true
else
" else {\n#{ @elseBody.compile(o) }\n#{@tab}}"
"#{ifPart}#{elsePart}"
# Compile the If as a conditional operator.
compileExpression: (o) ->

View File

@ -20,7 +20,7 @@ helpers.extend global, quit: -> process.exit(0)
# of exiting.
run = (buffer) ->
try
val = CoffeeScript.eval buffer.toString(), noWrap: true, globals: true, fileName: 'repl'
val = CoffeeScript.eval buffer.toString(), wrap: false, globals: true, fileName: 'repl'
puts inspect val if val isnt undefined
catch err
puts err.stack or err.toString()

View File

@ -328,7 +328,7 @@ IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = [
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY', 'TRUE', 'FALSE'
'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY',
'@', '->', '=>', '[', '(', '{'
]

View File

@ -26,4 +26,8 @@ tester = ->
@example = -> 'example function'
this
ok tester().example() is 'example function'
ok tester().example() is 'example function'
try throw CoffeeScript.tokens 'in = 1'
catch e then eq e.message, 'Reserved word "in" on line 1 can\'t be assigned'

View File

@ -2,17 +2,17 @@
CoffeeScript = require('./../lib/coffee-script')
Lexer = require('./../lib/lexer')
js = CoffeeScript.compile("one\r\ntwo", {noWrap: on})
js = CoffeeScript.compile("one\r\ntwo", {wrap: off})
ok js is "one;\ntwo;"
global.resultArray = []
CoffeeScript.run("resultArray.push i for i of global", {noWrap: on, globals: on, fileName: 'tests'})
CoffeeScript.run("resultArray.push i for i of global", {wrap: off, globals: on, fileName: 'tests'})
ok 'setInterval' in global.resultArray
ok 'passed' is CoffeeScript.eval '"passed"', noWrap: on, globals: on, fileName: 'tests'
ok 'passed' is CoffeeScript.eval '"passed"', wrap: off, globals: on, fileName: 'tests'
#750
try

View File

@ -47,3 +47,7 @@ loop
list.push i * 2
ok list.join(' ') is '8 6 4 2'
#759: `if` within `while` condition
2 while if 1 then 0