let's try to merge these indexOf patches.

This commit is contained in:
Jeremy Ashkenas 2010-10-19 23:27:15 -04:00
parent c1d24944dc
commit 113d7ce98f
9 changed files with 113 additions and 114 deletions

View File

@ -12,9 +12,6 @@
}
return -1;
}));
exports.include = function(list, value) {
return indexOf(list, value) >= 0;
};
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
};

View File

@ -1,7 +1,11 @@
(function() {
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, 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, INDEXABLE, 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, last, op, starts;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) if (this[i] === item) return i;
return -1;
};
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'), count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
exports.Lexer = (function() {
Lexer = (function() {
function Lexer() {
@ -32,7 +36,7 @@
return (new Rewriter).rewrite(this.tokens);
};
Lexer.prototype.identifierToken = function() {
var colon, forcedIdentifier, id, input, match, tag;
var _ref2, colon, forcedIdentifier, id, input, match, tag;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return false;
}
@ -44,15 +48,15 @@
}
forcedIdentifier = colon || this.tagAccessor();
tag = 'IDENTIFIER';
if (include(JS_KEYWORDS, id) || !forcedIdentifier && include(COFFEE_KEYWORDS, id)) {
if ((__indexOf.call(JS_KEYWORDS, id) >= 0) || !forcedIdentifier && (__indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
tag = id.toUpperCase();
if (tag === 'WHEN' && include(LINE_BREAK, this.tag())) {
if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
} else if (include(UNARY, tag)) {
} else if (__indexOf.call(UNARY, tag) >= 0) {
tag = 'UNARY';
} else if (include(RELATION, tag)) {
} else if (__indexOf.call(RELATION, tag) >= 0) {
if (tag !== 'INSTANCEOF' && this.seenFor) {
this.seenFor = false;
tag = 'FOR' + tag;
@ -65,12 +69,12 @@
}
}
}
if (include(JS_FORBIDDEN, id)) {
if (__indexOf.call(JS_FORBIDDEN, id) >= 0) {
if (forcedIdentifier) {
tag = 'IDENTIFIER';
id = new String(id);
id.reserved = true;
} else if (include(RESERVED, id)) {
} else if (__indexOf.call(RESERVED, id) >= 0) {
this.identifierError(id);
}
}
@ -80,9 +84,9 @@
}
if (id === '!') {
tag = 'UNARY';
} else if (include(LOGIC, id)) {
} else if (__indexOf.call(LOGIC, id) >= 0) {
tag = 'LOGIC';
} else if (include(BOOL, tag)) {
} else if (__indexOf.call(BOOL, tag) >= 0) {
id = tag.toLowerCase();
tag = 'BOOL';
}
@ -181,14 +185,14 @@
return true;
};
Lexer.prototype.regexToken = function() {
var match, regex;
var _ref2, match, regex;
if (this.chunk.charAt(0) !== '/') {
return false;
}
if (match = HEREGEX.exec(this.chunk)) {
return this.heregexToken(match);
}
if (include(NOT_REGEX, this.tag())) {
if (_ref2 = this.tag(), __indexOf.call(NOT_REGEX, _ref2) >= 0) {
return false;
}
if (!(match = REGEX.exec(this.chunk))) {
@ -322,7 +326,7 @@
return true;
};
Lexer.prototype.literalToken = function() {
var _ref2, match, prev, tag, value;
var _ref2, _ref3, _ref4, _ref5, match, prev, tag, value;
if (match = OPERATOR.exec(this.chunk)) {
value = match[0];
if (CODE.test(value)) {
@ -335,10 +339,10 @@
tag = value;
prev = last(this.tokens);
if (value === '=' && prev) {
if (!prev[1].reserved && include(JS_FORBIDDEN, prev[1])) {
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
this.assignmentError();
}
if (((_ref2 = prev[1]) === '||' || _ref2 === '&&')) {
if (((_ref3 = prev[1]) === '||' || _ref3 === '&&')) {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] += '=';
return true;
@ -346,27 +350,27 @@
}
if (';' === value) {
tag = 'TERMINATOR';
} else if (include(LOGIC, value)) {
} else if (__indexOf.call(LOGIC, value) >= 0) {
tag = 'LOGIC';
} else if (include(MATH, value)) {
} else if (__indexOf.call(MATH, value) >= 0) {
tag = 'MATH';
} else if (include(COMPARE, value)) {
} else if (__indexOf.call(COMPARE, value) >= 0) {
tag = 'COMPARE';
} else if (include(COMPOUND_ASSIGN, value)) {
} else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) {
tag = 'COMPOUND_ASSIGN';
} else if (include(UNARY, value)) {
} else if (__indexOf.call(UNARY, value) >= 0) {
tag = 'UNARY';
} else if (include(SHIFT, value)) {
} else if (__indexOf.call(SHIFT, value) >= 0) {
tag = 'SHIFT';
} else if (value === '?' && ((prev != null) ? prev.spaced : undefined)) {
tag = 'LOGIC';
} else if (prev && !prev.spaced) {
if (value === '(' && include(CALLABLE, prev[0])) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && include(INDEXABLE, prev[0])) {
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
tag = 'INDEX_START';
switch (prev[0]) {
case '?':

View File

@ -1,14 +1,17 @@
(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, 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, last, merge, starts, utility;
var __extends = function(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
if (typeof parent.extended === "function") parent.extended(child);
child.__super__ = parent.prototype;
}, __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) if (this[i] === item) return i;
return -1;
};
Scope = require('./scope').Scope;
_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;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
YES = function() {
return true;
};
@ -983,7 +986,7 @@
Assign.prototype.children = ['variable', 'value'];
Assign.prototype.topSensitive = YES;
Assign.prototype.compileNode = function(o) {
var ifn, isValue, match, name, stmt, top, val;
var _ref2, ifn, isValue, match, name, stmt, top, val;
if (isValue = this.variable instanceof Value) {
if (this.variable.isArray() || this.variable.isObject()) {
return this.compilePatternMatch(o);
@ -995,7 +998,7 @@
delete o.top;
return ifn.compile(o);
}
if (include(this.CONDITIONAL, this.context)) {
if (_ref2 = this.context, __indexOf.call(this.CONDITIONAL, _ref2) >= 0) {
return this.compileConditional(o);
}
}
@ -1391,7 +1394,8 @@
return this.operator !== '!' || this.first.isComplex();
};
Op.prototype.isChainable = function() {
return include(this.CHAINABLE, this.operator);
var _ref2;
return (_ref2 = this.operator, __indexOf.call(this.CHAINABLE, _ref2) >= 0);
};
Op.prototype.invert = function() {
var _ref2;
@ -1404,12 +1408,12 @@
return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator);
};
Op.prototype.compileNode = function(o) {
var ifn;
var _ref2, ifn;
if (this.isChainable() && this.first.unwrap().isChainable()) {
return this.compileChain(o);
}
if (this.isUnary()) {
if (include(this.MUTATORS, this.operator) && (ifn = If.unfoldSoak(o, this, 'first'))) {
if ((_ref2 = this.operator, __indexOf.call(this.MUTATORS, _ref2) >= 0) && (ifn = If.unfoldSoak(o, this, 'first'))) {
return ifn.compile(o);
}
return this.compileUnary(o);
@ -1439,8 +1443,8 @@
return new Existence(fst).compile(o) + (" ? " + ref + " : " + (this.second.compile(o)));
};
Op.prototype.compileUnary = function(o) {
var parts, space;
space = include(this.PREFIX_OPERATORS, this.operator) ? ' ' : '';
var _ref2, parts, space;
space = (_ref2 = this.operator, __indexOf.call(this.PREFIX_OPERATORS, _ref2) >= 0) ? ' ' : '';
parts = [this.operator, space, this.first.compile(o)];
return (this.flip ? parts.reverse() : parts).join('');
};
@ -1480,14 +1484,15 @@
return "(" + (tests.join(' || ')) + ")";
};
In.prototype.compileLoopTest = function(o) {
var _ref2, obj1, obj2, prefix;
var _ref2, code, obj1, obj2, prefix;
_ref2 = this.object.compileReference(merge(o, {
top: true
}), {
precompile: true
}), obj1 = _ref2[0], obj2 = _ref2[1];
prefix = obj1 !== obj2 ? ("" + obj1 + ", ") : '';
return "(" + prefix + (utility('indexOf')) + ".call(" + (this.array.compile(o)) + ", " + obj2 + ") >= 0)";
code = ("" + prefix + (utility('indexOf')) + ".call(" + (this.array.compile(o)) + ", " + obj2 + ") >= 0");
return this.parenthetical ? code : ("(" + code + ")");
};
return In;
})();

View File

@ -1,6 +1,9 @@
(function() {
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, _i, _len, _ref, include, left, rite;
include = require('./helpers').include;
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, _i, _len, _ref, left, rite;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) if (this[i] === item) return i;
return -1;
};
exports.Rewriter = (function() {
function Rewriter() {
return this;
@ -32,7 +35,7 @@
return true;
};
exports.Rewriter.prototype.detectEnd = function(i, condition, action) {
var levels, token, tokens;
var _ref, _ref2, levels, token, tokens;
tokens = this.tokens;
levels = 0;
while (token = tokens[i]) {
@ -42,9 +45,9 @@
if (!token || levels < 0) {
return action.call(this, token, i - 1);
}
if (include(EXPRESSION_START, token[0])) {
if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
levels += 1;
} else if (include(EXPRESSION_END, token[0])) {
} else if (_ref2 = token[0], __indexOf.call(EXPRESSION_END, _ref2) >= 0) {
levels -= 1;
}
i += 1;
@ -94,7 +97,8 @@
};
exports.Rewriter.prototype.removeMidExpressionNewlines = function() {
return this.scanTokens(function(token, i, tokens) {
if (!(token[0] === 'TERMINATOR' && include(EXPRESSION_CLOSE, this.tag(i + 1)))) {
var _ref;
if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) {
return 1;
}
tokens.splice(i, 1);
@ -149,12 +153,12 @@
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
};
return this.scanTokens(function(token, i, tokens) {
var idx, tag, tok;
if (include(EXPRESSION_START, tag = token[0])) {
var _ref, idx, tag, tok;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag);
return 1;
}
if (include(EXPRESSION_END, tag)) {
if (__indexOf.call(EXPRESSION_END, tag) >= 0) {
stack.pop();
return 1;
}
@ -182,27 +186,27 @@
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
};
return this.scanTokens(function(token, i, tokens) {
var callObject, next, prev, seenSingle, tag;
var _ref, _ref2, callObject, next, prev, seenSingle, tag;
tag = token[0];
if (tag === 'CLASS') {
classLine = true;
}
prev = tokens[i - 1];
next = tokens[i + 1];
callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && include(IMPLICIT_FUNC, prev[0]);
callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref) >= 0);
seenSingle = false;
if (include(LINEBREAKS, tag)) {
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
classLine = false;
}
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || include(IMPLICIT_FUNC, prev[0])) && (include(IMPLICIT_CALL, tag) || include(IMPLICIT_UNSPACED_CALL, tag) && !token.spaced))) {
if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && ((__indexOf.call(IMPLICIT_CALL, tag) >= 0) || (__indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0) && !token.spaced))) {
return 1;
}
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
this.detectEnd(i + (callObject ? 2 : 1), function(token, i) {
var post;
var _ref3, post;
if (!seenSingle && token.fromThen) {
return true;
}
@ -213,7 +217,7 @@
if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && include(IMPLICIT_END, tag) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !include(IMPLICIT_BLOCK, this.tag(i - 1)) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !(_ref3 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref3) >= 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
}, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
@ -233,7 +237,7 @@
tokens.splice.apply(tokens, [i + 2, 0].concat(this.indentation(token)));
return 4;
}
if (include(SINGLE_LINERS, tag) && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
if ((__indexOf.call(SINGLE_LINERS, tag) >= 0) && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
starter = tag;
_ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1];
if (starter === 'THEN') {
@ -242,7 +246,8 @@
indent.generated = (outdent.generated = true);
tokens.splice(i + 1, 0, indent);
condition = function(token, i) {
return token[1] !== ';' && include(SINGLE_CLOSERS, token[0]) && !(token[0] === 'ELSE' && !(starter === 'IF' || starter === 'THEN'));
var _ref3;
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && !(starter === 'IF' || starter === 'THEN'));
};
action = function(token, i) {
return this.tokens.splice(this.tag(i - 1) === ',' ? i - 1 : i, 0, outdent);
@ -320,12 +325,12 @@
(debt[key] = 0);
}
return this.scanTokens(function(token, i, tokens) {
var inv, match, mtag, oppos, tag, val;
if (include(EXPRESSION_START, tag = token[0])) {
var _ref, inv, match, mtag, oppos, tag, val;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push(token);
return 1;
}
if (!include(EXPRESSION_END, tag)) {
if (!(__indexOf.call(EXPRESSION_END, tag) >= 0)) {
return 1;
}
if (debt[(inv = INVERSES[tag])] > 0) {

View File

@ -14,10 +14,6 @@ indexOf = exports.indexOf = Array.indexOf or
return index
-1
# Does a list include a value?
exports.include = (list, value) ->
indexOf(list, value) >= 0
# Peek at the beginning of a given string to see if it matches a sequence.
exports.starts = (string, literal, start) ->
literal is string.substr start, literal.length

View File

@ -10,7 +10,7 @@
{Rewriter} = require './rewriter'
# Import the helpers we need.
{include, count, starts, compact, last} = require './helpers'
{count, starts, compact, last} = require './helpers'
# The Lexer Class
# ---------------
@ -80,16 +80,16 @@ exports.Lexer = class Lexer
return true
forcedIdentifier = colon or @tagAccessor()
tag = 'IDENTIFIER'
if include(JS_KEYWORDS, id) or
not forcedIdentifier and include(COFFEE_KEYWORDS, id)
if id in JS_KEYWORDS or
not forcedIdentifier and id in COFFEE_KEYWORDS
tag = id.toUpperCase()
if tag is 'WHEN' and include LINE_BREAK, @tag()
if tag is 'WHEN' and @tag() in LINE_BREAK
tag = 'LEADING_WHEN'
else if tag is 'FOR'
@seenFor = yes
else if include UNARY, tag
else if tag in UNARY
tag = 'UNARY'
else if include RELATION, tag
else if tag in RELATION
if tag isnt 'INSTANCEOF' and @seenFor
@seenFor = no
tag = 'FOR' + tag
@ -98,20 +98,20 @@ exports.Lexer = class Lexer
if @value() is '!'
@tokens.pop()
id = '!' + id
if include JS_FORBIDDEN, id
if id in JS_FORBIDDEN
if forcedIdentifier
tag = 'IDENTIFIER'
id = new String id
id.reserved = yes
else if include RESERVED, id
else if id in RESERVED
@identifierError id
unless forcedIdentifier
tag = id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
if id is '!'
tag = 'UNARY'
else if include LOGIC, id
else if id in LOGIC
tag = 'LOGIC'
else if include BOOL, tag
else if tag in BOOL
id = tag.toLowerCase()
tag = 'BOOL'
@token tag, id
@ -187,7 +187,7 @@ exports.Lexer = class Lexer
regexToken: ->
return false if @chunk.charAt(0) isnt '/'
return @heregexToken match if match = HEREGEX.exec @chunk
return false if include NOT_REGEX, @tag()
return false if @tag() in NOT_REGEX
return false unless match = REGEX.exec @chunk
[regex] = match
@token 'REGEX', if regex is '//' then '/(?:)/' else regex
@ -313,24 +313,24 @@ exports.Lexer = class Lexer
tag = value
prev = last @tokens
if value is '=' and prev
@assignmentError() if not prev[1].reserved and include JS_FORBIDDEN, prev[1]
@assignmentError() if not prev[1].reserved and prev[1] in JS_FORBIDDEN
if prev[1] in ['||', '&&']
prev[0] = 'COMPOUND_ASSIGN'
prev[1] += '='
return true
if ';' is value then tag = 'TERMINATOR'
else if include LOGIC , value then tag = 'LOGIC'
else if include MATH , value then tag = 'MATH'
else if include COMPARE , value then tag = 'COMPARE'
else if include COMPOUND_ASSIGN, value then tag = 'COMPOUND_ASSIGN'
else if include UNARY , value then tag = 'UNARY'
else if include SHIFT , value then tag = 'SHIFT'
if ';' is value then tag = 'TERMINATOR'
else if value in LOGIC then tag = 'LOGIC'
else if value in MATH then tag = 'MATH'
else if value in COMPARE then tag = 'COMPARE'
else if value in COMPOUND_ASSIGN then tag = 'COMPOUND_ASSIGN'
else if value in UNARY then tag = 'UNARY'
else if value in SHIFT then tag = 'SHIFT'
else if value is '?' and prev?.spaced then tag = 'LOGIC'
else if prev and not prev.spaced
if value is '(' and include CALLABLE, prev[0]
if value is '(' and prev[0] in CALLABLE
prev[0] = 'FUNC_EXIST' if prev[0] is '?'
tag = 'CALL_START'
else if value is '[' and include INDEXABLE, prev[0]
else if value is '[' and prev[0] in INDEXABLE
tag = 'INDEX_START'
switch prev[0]
when '?' then prev[0] = 'INDEX_SOAK'

View File

@ -6,7 +6,7 @@
{Scope} = require './scope'
# Import the helpers we plan to use.
{compact, flatten, merge, del, include, starts, ends, last} = require './helpers'
{compact, flatten, merge, del, starts, ends, last} = require './helpers'
# Constant functions for nodes that don't need customization.
YES = -> yes
@ -857,7 +857,7 @@ exports.Assign = class Assign extends Base
if ifn = If.unfoldSoak o, this, 'variable'
delete o.top
return ifn.compile o
return @compileConditional o if include @CONDITIONAL, @context
return @compileConditional o if @context in @CONDITIONAL
top = del o, 'top'
stmt = del o, 'asStatement'
name = @variable.compile o
@ -1192,7 +1192,7 @@ exports.Op = class Op extends Base
isComplex: -> @operator isnt '!' or @first.isComplex()
isChainable: ->
include(@CHAINABLE, @operator)
@operator in @CHAINABLE
invert: ->
if @operator in ['===', '!==']
@ -1209,7 +1209,7 @@ exports.Op = class Op extends Base
compileNode: (o) ->
return @compileChain o if @isChainable() and @first.unwrap().isChainable()
if @isUnary()
return ifn.compile o if include(@MUTATORS, @operator) and ifn = If.unfoldSoak o, this, 'first'
return ifn.compile o if @operator in @MUTATORS and ifn = If.unfoldSoak o, this, 'first'
return @compileUnary o
return @compileExistence o if @operator is '?'
@first.tags.front = @tags.front
@ -1237,7 +1237,7 @@ exports.Op = class Op extends Base
# Compile a unary **Op**.
compileUnary: (o) ->
space = if include @PREFIX_OPERATORS, @operator then ' ' else ''
space = if @operator in @PREFIX_OPERATORS then ' ' else ''
parts = [@operator, space, @first.compile(o)]
(if @flip then parts.reverse() else parts).join ''
@ -1264,7 +1264,8 @@ exports.In = class In extends Base
compileLoopTest: (o) ->
[obj1, obj2] = @object.compileReference merge(o, top: yes), precompile: yes
prefix = if obj1 isnt obj2 then "#{obj1}, " else ''
"(#{prefix}#{utility 'indexOf'}.call(#{@array.compile o}, #{obj2}) >= 0)"
code = "#{prefix}#{utility 'indexOf'}.call(#{@array.compile o}, #{obj2}) >= 0"
if @parenthetical then code else "(#{code})"
#### Try

View File

@ -5,9 +5,6 @@
# shorthand into the unambiguous long form, add implicit indentation and
# parentheses, balance incorrect nestings, and generally clean things up.
# Import the helpers we need.
{include} = require './helpers'
# The **Rewriter** class is used by the [Lexer](lexer.html), directly against
# its internal array of tokens.
class exports.Rewriter
@ -51,9 +48,9 @@ class exports.Rewriter
while token = tokens[i]
return action.call this, token, i if levels is 0 and condition.call this, token, i
return action.call this, token, i - 1 if not token or levels < 0
if include EXPRESSION_START, token[0]
if token[0] in EXPRESSION_START
levels += 1
else if include EXPRESSION_END, token[0]
else if token[0] in EXPRESSION_END
levels -= 1
i += 1
i - 1
@ -93,7 +90,7 @@ class exports.Rewriter
# this, remove their trailing newlines.
removeMidExpressionNewlines: ->
@scanTokens (token, i, tokens) ->
return 1 unless token[0] is 'TERMINATOR' and include EXPRESSION_CLOSE, @tag(i + 1)
return 1 unless token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE
tokens.splice i, 1
0
@ -131,10 +128,10 @@ class exports.Rewriter
tag is ',' and one?[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT']
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
@scanTokens (token, i, tokens) ->
if include EXPRESSION_START, tag = token[0]
if (tag = token[0]) in EXPRESSION_START
stack.push if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag
return 1
if include EXPRESSION_END, tag
if tag in EXPRESSION_END
stack.pop()
return 1
return 1 unless tag is ':' and stack[stack.length - 1] isnt '{'
@ -162,22 +159,22 @@ class exports.Rewriter
next = tokens[i + 1]
callObject = not classLine and tag is 'INDENT' and
next and next.generated and next[0] is '{' and
prev and include(IMPLICIT_FUNC, prev[0])
prev and prev[0] in IMPLICIT_FUNC
seenSingle = no
classLine = no if include LINEBREAKS, tag
classLine = no if tag in LINEBREAKS
token.call = yes if prev and not prev.spaced and tag is '?'
return 1 unless callObject or
prev?.spaced and (prev.call or include(IMPLICIT_FUNC, prev[0])) and
(include(IMPLICIT_CALL, tag) or include(IMPLICIT_UNSPACED_CALL, tag) and not token.spaced)
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
(tag in IMPLICIT_CALL or tag in IMPLICIT_UNSPACED_CALL and not token.spaced)
tokens.splice i, 0, ['CALL_START', '(', token[2]]
@detectEnd i + (if callObject then 2 else 1), (token, i) ->
return yes if not seenSingle and token.fromThen
[tag] = token
seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>']
return yes if tag is 'PROPERTY_ACCESS' and @tag(i - 1) is 'OUTDENT'
not token.generated and @tag(i - 1) isnt ',' and include(IMPLICIT_END, tag) and
not token.generated and @tag(i - 1) isnt ',' and tag in IMPLICIT_END and
(tag isnt 'INDENT' or
(@tag(i - 2) isnt 'CLASS' and not include(IMPLICIT_BLOCK, @tag(i - 1)) and
(@tag(i - 2) isnt 'CLASS' and not (@tag(i - 1) in IMPLICIT_BLOCK) and
not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))
, action
prev[0] = 'FUNC_EXIST' if prev[0] is '?'
@ -196,7 +193,7 @@ class exports.Rewriter
if tag is 'CATCH' and @tag(i + 2) in ['TERMINATOR', 'FINALLY']
tokens.splice i + 2, 0, @indentation(token)...
return 4
if include(SINGLE_LINERS, tag) and @tag(i + 1) isnt 'INDENT' and
if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and
not (tag is 'ELSE' and @tag(i + 1) is 'IF')
starter = tag
[indent, outdent] = @indentation token
@ -204,7 +201,7 @@ class exports.Rewriter
indent.generated = outdent.generated = true
tokens.splice i + 1, 0, indent
condition = (token, i) ->
token[1] isnt ';' and include(SINGLE_CLOSERS, token[0]) and
token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
not (token[0] is 'ELSE' and starter not in ['IF', 'THEN'])
action = (token, i) ->
@tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent
@ -265,10 +262,10 @@ class exports.Rewriter
debt = {}
(debt[key] = 0) for all key of INVERSES
@scanTokens (token, i, tokens) ->
if include EXPRESSION_START, tag = token[0]
if (tag = token[0]) in EXPRESSION_START
stack.push token
return 1
return 1 unless include EXPRESSION_END, tag
return 1 unless tag in EXPRESSION_END
if debt[inv = INVERSES[tag]] > 0
debt[inv] -= 1
tokens.splice i, 1

View File

@ -1,4 +1,4 @@
{indexOf, include, starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
{indexOf, starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
array = [0..4]
string = array.join ''
@ -10,12 +10,6 @@ eq 2, indexOf array, 2
eq 4, indexOf array, 4
eq(-1, indexOf array, 6)
# Test `include`
ok include array, 0
ok include array, 2
ok include array, 4
ok not include array, 6
# Test `starts`
ok starts string, '012'
ok starts string, '34', 3