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
22 changed files with 451 additions and 910 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,11 +2,12 @@
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments; var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
exports.OptionParser = (function() { exports.OptionParser = (function() {
OptionParser = (function() { OptionParser = (function() {
return function OptionParser(rules, banner) { function OptionParser(rules, banner) {
this.banner = banner; this.banner = banner;
this.rules = buildRules(rules); this.rules = buildRules(rules);
return this; return this;
}; };
return OptionParser;
})(); })();
OptionParser.prototype.parse = function(args) { OptionParser.prototype.parse = function(args) {
var _i, _len, _len2, _ref, arg, i, isOption, matchedRule, options, rule, value; 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; var val;
try { try {
val = CoffeeScript.eval(buffer.toString(), { val = CoffeeScript.eval(buffer.toString(), {
noWrap: true, wrap: false,
globals: true, globals: true,
fileName: 'repl' 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; 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; include = require('./helpers').include;
exports.Rewriter = (function() { exports.Rewriter = (function() {
return function Rewriter() {}; function Rewriter() {};
return Rewriter;
})(); })();
exports.Rewriter.prototype.rewrite = function(_arg) { exports.Rewriter.prototype.rewrite = function(_arg) {
this.tokens = _arg; this.tokens = _arg;
@@ -365,7 +366,7 @@
} }
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; 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_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT']; IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ helpers.extend global, quit: -> process.exit(0)
# of exiting. # of exiting.
run = (buffer) -> run = (buffer) ->
try 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 puts inspect val if val isnt undefined
catch err catch err
puts err.stack or err.toString() 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. # If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = [ IMPLICIT_CALL = [
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS' '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

@@ -27,3 +27,7 @@ tester = ->
this 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') CoffeeScript = require('./../lib/coffee-script')
Lexer = require('./../lib/lexer') 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;" ok js is "one;\ntwo;"
global.resultArray = [] 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 '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 #750
try try

View File

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