added `last` to helpers

This commit is contained in:
satyr 2010-09-28 21:52:51 +09:00
parent c064c90ee9
commit b2313beaf4
7 changed files with 128 additions and 135 deletions

View File

@ -38,7 +38,7 @@
exports.count = function(string, letter) {
var num, pos;
num = (pos = 0);
while (0 < (pos = 1 + string.indexOf(letter, pos))) {
while (pos = 1 + string.indexOf(letter, pos)) {
num++;
}
return num;
@ -64,4 +64,7 @@
delete obj[key];
return val;
};
exports.last = function(array, back) {
return array[array.length - (back || 0) - 1];
};
}).call(this);

View File

@ -1,5 +1,5 @@
(function() {
var ASSIGNED, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, CONVERSIONS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, SHIFT, SIMPLESTR, UNARY, WHITESPACE, _ref, compact, count, include, starts;
var ASSIGNED, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, CONVERSIONS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, SHIFT, SIMPLESTR, UNARY, WHITESPACE, _ref, compact, count, include, last, starts;
var __slice = Array.prototype.slice;
_ref = require('./rewriter');
Rewriter = _ref.Rewriter;
@ -8,6 +8,7 @@
count = _ref.count;
starts = _ref.starts;
compact = _ref.compact;
last = _ref.last;
exports.Lexer = (function() {
Lexer = function() {};
Lexer.prototype.tokenize = function(code, options) {
@ -212,7 +213,7 @@
indent = match[0];
this.line += count(indent, '\n');
this.i += indent.length;
prev = this.prev(2);
prev = last(this.tokens, 1);
size = indent.length - 1 - indent.lastIndexOf('\n');
nextCharacter = NEXT_CHARACTER.exec(this.chunk)[1];
noNewlines = (('.' === nextCharacter || ',' === nextCharacter)) || this.unfinished();
@ -270,7 +271,7 @@
if (!(match = WHITESPACE.exec(this.chunk))) {
return false;
}
prev = this.prev();
prev = last(this.tokens);
if (prev) {
prev.spaced = true;
}
@ -290,7 +291,7 @@
return true;
};
Lexer.prototype.literalToken = function() {
var _ref2, match, prev, space, spaced, tag, value;
var _ref2, match, prev, space, spaced, tag, val, value;
if (match = this.chunk.match(OPERATOR)) {
_ref2 = match;
value = _ref2[0];
@ -302,14 +303,15 @@
value = this.chunk.charAt(0);
}
this.i += value.length;
spaced = (prev = this.prev()) && prev.spaced;
prev = last(this.tokens);
spaced = prev == null ? undefined : prev.spaced;
tag = value;
if (value === '=') {
if (include(JS_FORBIDDEN, this.value())) {
if (include(JS_FORBIDDEN, val = this.value())) {
this.assignmentError();
}
if (('or' === (_ref2 = this.value()) || 'and' === _ref2)) {
this.tokens.splice(this.tokens.length - 1, 1, ['COMPOUND_ASSIGN', CONVERSIONS[this.value()] + '=', prev[2]]);
if (('or' === val || 'and' === val)) {
this.tokens.splice(-1, 1, ['COMPOUND_ASSIGN', CONVERSIONS[val] + '=', prev[2]]);
return true;
}
}
@ -337,10 +339,10 @@
tag = 'INDEX_START';
switch (this.tag()) {
case '?':
this.tag(1, 'INDEX_SOAK');
this.tag(0, 'INDEX_SOAK');
break;
case '::':
this.tag(1, 'INDEX_PROTO');
this.tag(0, 'INDEX_PROTO');
break;
}
}
@ -350,18 +352,18 @@
};
Lexer.prototype.tagAccessor = function() {
var accessor, prev;
if ((!(prev = this.prev())) || (prev && prev.spaced)) {
if (!(prev = last(this.tokens)) || prev.spaced) {
return false;
}
accessor = (function() {
if (prev[1] === '::') {
return this.tag(1, 'PROTOTYPE_ACCESS');
} else if (prev[1] === '.' && this.value(2) !== '.') {
if (this.tag(2) === '?') {
this.tag(1, 'SOAK_ACCESS');
return this.tag(0, 'PROTOTYPE_ACCESS');
} else if (prev[1] === '.' && this.value(1) !== '.') {
if (this.tag(1) === '?') {
this.tag(0, 'SOAK_ACCESS');
return this.tokens.splice(-2, 1);
} else {
return this.tag(1, 'PROPERTY_ACCESS');
return this.tag(0, 'PROPERTY_ACCESS');
}
} else {
return prev[0] === '@';
@ -402,11 +404,9 @@
if (this.tag() !== ')') {
return null;
}
i = 0;
i = this.tokens.length;
while (true) {
i += 1;
tok = this.prev(i);
if (!tok) {
if (!(tok = this.tokens[--i])) {
return null;
}
switch (tok[0]) {
@ -449,7 +449,7 @@
_ref3 = pair;
open = _ref3[0];
close = _ref3[1];
if (levels.length && starts(str, close, i) && levels[levels.length - 1] === pair) {
if (levels.length && starts(str, close, i) && last(levels) === pair) {
levels.pop();
i += close.length - 1;
if (!(levels.length)) {
@ -563,30 +563,21 @@
};
Lexer.prototype.tag = function(index, newTag) {
var tok;
if (!(tok = this.prev(index))) {
if (!(tok = last(this.tokens, index))) {
return null;
}
if (typeof newTag !== "undefined" && newTag !== null) {
return (tok[0] = newTag);
}
return tok[0];
return (tok[0] = (typeof newTag !== "undefined" && newTag !== null) ? newTag : tok[0]);
};
Lexer.prototype.value = function(index, val) {
var tok;
if (!(tok = this.prev(index))) {
if (!(tok = last(this.tokens, index))) {
return null;
}
if (typeof val !== "undefined" && val !== null) {
return (tok[1] = val);
}
return tok[1];
};
Lexer.prototype.prev = function(index) {
return this.tokens[this.tokens.length - (index || 1)];
return (tok[1] = (typeof val !== "undefined" && val !== null) ? val : tok[1]);
};
Lexer.prototype.unfinished = function() {
var prev, value;
return (prev = this.prev(2)) && prev[0] !== '.' && (value = this.value()) && NO_NEWLINE.test(value) && !CODE.test(value) && !ASSIGNED.test(this.chunk);
return (prev = last(this.tokens, 1)) && prev[0] !== '.' && (value = this.value()) && NO_NEWLINE.test(value) && !CODE.test(value) && !ASSIGNED.test(this.chunk);
};
Lexer.prototype.escapeLines = function(str, heredoc) {
return str.replace(MULTILINER, heredoc ? '\\n' : '');

View File

@ -1,5 +1,5 @@
(function() {
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, literal, merge, starts, utility;
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, last, literal, merge, starts, utility;
var __extends = function(child, parent) {
var ctor = function(){};
ctor.prototype = parent.prototype;
@ -19,6 +19,7 @@
indexOf = _ref.indexOf;
starts = _ref.starts;
ends = _ref.ends;
last = _ref.last;
YES = function() {
return true;
};
@ -191,16 +192,14 @@
return this.expressions.length === 0;
};
Expressions.prototype.makeReturn = function() {
var idx, last;
idx = this.expressions.length - 1;
last = this.expressions[idx];
if (last instanceof CommentNode) {
last = this.expressions[idx -= 1];
var end, idx;
end = this.expressions[(idx = this.expressions.length - 1)];
if (end instanceof CommentNode) {
end = this.expressions[idx -= 1];
}
if (!last || last instanceof ReturnNode) {
return this;
if (end && !(end instanceof ReturnNode)) {
this.expressions[idx] = end.makeReturn();
}
this.expressions[idx] = last.makeReturn();
return this;
};
Expressions.prototype.compile = function(o) {
@ -335,10 +334,10 @@
return this.base instanceof ObjectNode && !this.hasProperties();
};
ValueNode.prototype.isSplice = function() {
return this.hasProperties() && this.properties[this.properties.length - 1] instanceof SliceNode;
return last(this.properties) instanceof SliceNode;
};
ValueNode.prototype.isComplex = function() {
return this.base.isComplex() || this.properties.length;
return this.base.isComplex() || this.hasProperties();
};
ValueNode.prototype.makeReturn = function() {
return this.hasProperties() ? ValueNode.__super__.makeReturn.call(this) : this.base.makeReturn();
@ -380,7 +379,7 @@
return !o.top || this.properties.length ? ValueNode.__super__.compile.call(this, o) : this.base.compile(o);
};
ValueNode.prototype.compileNode = function(o) {
var _i, _len, _ref2, baseline, complete, copy, hasSoak, i, me, only, op, part, prevcomp, prop, props, temp;
var _i, _len, _ref2, baseline, complete, copy, hasSoak, i, me, only, op, part, prop, props, temp;
only = del(o, 'onlyFirst');
op = this.tags.operation;
props = only ? this.properties.slice(0, -1) : this.properties;
@ -413,7 +412,7 @@
if (prop.soakNode) {
if (i === 0 && this.base.isComplex()) {
temp = o.scope.freeVariable('ref');
complete = ("(" + (baseline = temp) + " = (" + (prevcomp = complete) + "))");
complete = ("(" + (baseline = temp) + " = (" + (complete) + "))");
}
complete = i === 0 && !o.scope.check(complete) ? ("(typeof " + (complete) + " === \"undefined\" || " + (baseline) + " === null)") : ("" + (complete) + " == null");
complete += ' ? undefined : ' + (baseline += prop.compile(o));
@ -493,7 +492,7 @@
}
op = this.tags.operation;
if (this.exist) {
if (this.variable instanceof ValueNode && this.variable.properties[this.variable.properties.length - 1] instanceof AccessorNode) {
if (this.variable instanceof ValueNode && last(this.variable.properties) instanceof AccessorNode) {
methodAccessor = this.variable.properties.pop();
_ref2 = this.variable.compileReference(o);
first = _ref2[0];
@ -771,7 +770,7 @@
}
return _result;
}).call(this);
lastNoncom = nonComments[nonComments.length - 1];
lastNoncom = last(nonComments);
props = (function() {
_result = []; _ref2 = this.properties;
for (i = 0, _len = _ref2.length; i < _len; i++) {
@ -949,7 +948,7 @@
return this.isValue() && (this.variable.isArray() || this.variable.isObject());
};
AssignNode.prototype.compileNode = function(o) {
var last, match, name, proto, stmt, top, val;
var end, match, name, proto, stmt, top, val;
top = del(o, 'top');
if (this.isStatement(o)) {
return this.compilePatternMatch(o);
@ -959,12 +958,12 @@
}
stmt = del(o, 'asStatement');
name = this.variable.compile(o);
last = this.isValue() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
end = this.isValue() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
match = name.match(this.PROTO_ASSIGN);
proto = match && match[1];
if (this.value instanceof CodeNode) {
if (last.match(IDENTIFIER)) {
this.value.name = last;
if (IDENTIFIER.test(end)) {
this.value.name = end;
}
if (proto) {
this.value.proto = proto;
@ -1202,25 +1201,26 @@
return "" + (utility('slice')) + ".call(" + (name) + ", " + (index) + (trail) + ")";
};
SplatNode.compileSplattedArray = function(list, o) {
var _len, _ref2, arg, args, code, i, last, prev;
var _len, _ref2, arg, args, code, end, i, prev;
args = [];
end = -1;
_ref2 = list;
for (i = 0, _len = _ref2.length; i < _len; i++) {
arg = _ref2[i];
code = arg.compile(o);
prev = args[(last = args.length - 1)];
prev = args[end];
if (!(arg instanceof SplatNode)) {
if (prev && starts(prev, '[') && ends(prev, ']')) {
args[last] = ("" + (prev.slice(0, -1)) + ", " + (code) + "]");
args[end] = ("" + (prev.slice(0, -1)) + ", " + (code) + "]");
continue;
} else if (prev && starts(prev, '.concat([') && ends(prev, '])')) {
args[last] = ("" + (prev.slice(0, -2)) + ", " + (code) + "])");
continue;
} else {
code = ("[" + (code) + "]");
}
if (prev && starts(prev, '.concat([') && ends(prev, '])')) {
args[end] = ("" + (prev.slice(0, -2)) + ", " + (code) + "])");
continue;
}
code = ("[" + (code) + "]");
}
args.push(i === 0 ? code : (".concat(" + (code) + ")"));
args[++end] = i === 0 ? code : (".concat(" + (code) + ")");
}
return args.join('');
};
@ -1756,7 +1756,7 @@
code += ("\n" + (this.idt(1)) + "case " + (condition.compile(o)) + ":");
}
code += ("\n" + (block.compile(o)));
if (!(exprs[exprs.length - 1] instanceof ReturnNode)) {
if (!(last(exprs) instanceof ReturnNode)) {
code += ("\n" + (idt) + "break;");
}
}

View File

@ -34,7 +34,7 @@ exports.compact = (array) ->
# Count the number of occurences of a character in a string.
exports.count = (string, letter) ->
num = pos = 0
num++ while 0 < pos = 1 + string.indexOf letter, pos
num++ while pos = 1 + string.indexOf letter, pos
num
# Merge objects, returning a fresh copy with attributes from both sides.
@ -61,3 +61,6 @@ exports.del = (obj, key) ->
val = obj[key]
delete obj[key]
val
# Gets the last item of an array(-like) object.
exports.last = (array, back) -> array[array.length - (back or 0) - 1]

View File

@ -10,7 +10,7 @@
{Rewriter} = require './rewriter'
# Import the helpers we need.
{include, count, starts, compact} = require './helpers'
{include, count, starts, compact, last} = require './helpers'
# The Lexer Class
# ---------------
@ -170,7 +170,7 @@ exports.Lexer = class Lexer
regexToken: ->
return false unless first = @chunk.match REGEX_START
return false if first[1] is ' ' and @tag() not in ['CALL_START', '=']
return false if include NOT_REGEX, @tag()
return false if include NOT_REGEX, @tag()
return false unless regex = @balancedToken ['/', '/']
return false unless end = @chunk[regex.length..].match REGEX_END
flags = end[0]
@ -206,7 +206,7 @@ exports.Lexer = class Lexer
indent = match[0]
@line += count indent, '\n'
@i += indent.length
prev = @prev 2
prev = last @tokens, 1
size = indent.length - 1 - indent.lastIndexOf '\n'
nextCharacter = NEXT_CHARACTER.exec(@chunk)[1]
noNewlines = (nextCharacter in ['.', ',']) or @unfinished()
@ -254,7 +254,7 @@ exports.Lexer = class Lexer
# as being "spaced", because there are some cases where it makes a difference.
whitespaceToken: ->
return false unless match = WHITESPACE.exec @chunk
prev = @prev()
prev = last @tokens
prev.spaced = true if prev
@i += match[0].length
true
@ -282,12 +282,13 @@ exports.Lexer = class Lexer
else
value = @chunk.charAt 0
@i += value.length
spaced = (prev = @prev()) and prev.spaced
prev = last @tokens
spaced = prev?.spaced
tag = value
if value is '='
@assignmentError() if include JS_FORBIDDEN, @value()
if @value() in ['or', 'and']
@tokens.splice(@tokens.length - 1, 1, ['COMPOUND_ASSIGN', CONVERSIONS[@value()] + '=', prev[2]])
@assignmentError() if include JS_FORBIDDEN, val = @value()
if val in ['or', 'and']
@tokens.splice(-1, 1, ['COMPOUND_ASSIGN', CONVERSIONS[val] + '=', prev[2]])
return true
if value is ';' then tag = 'TERMINATOR'
else if include(LOGIC, value) then tag = 'LOGIC'
@ -303,8 +304,8 @@ exports.Lexer = class Lexer
else if value is '['
tag = 'INDEX_START'
switch @tag()
when '?' then @tag 1, 'INDEX_SOAK'
when '::' then @tag 1, 'INDEX_PROTO'
when '?' then @tag 0, 'INDEX_SOAK'
when '::' then @tag 0, 'INDEX_PROTO'
@token tag, value
true
@ -315,15 +316,15 @@ exports.Lexer = class Lexer
# if it's a special kind of accessor. Return `true` if any type of accessor
# is the previous token.
tagAccessor: ->
return false if (not prev = @prev()) or (prev and prev.spaced)
return false if not (prev = last @tokens) or prev.spaced
accessor = if prev[1] is '::'
@tag 1, 'PROTOTYPE_ACCESS'
else if prev[1] is '.' and @value(2) isnt '.'
if @tag(2) is '?'
@tag(1, 'SOAK_ACCESS')
@tag 0, 'PROTOTYPE_ACCESS'
else if prev[1] is '.' and @value(1) isnt '.'
if @tag(1) is '?'
@tag(0, 'SOAK_ACCESS')
@tokens.splice(-2, 1)
else
@tag 1, 'PROPERTY_ACCESS'
@tag 0, 'PROPERTY_ACCESS'
else
prev[0] is '@'
if accessor then 'accessor' else false
@ -348,11 +349,9 @@ exports.Lexer = class Lexer
# parameters specially in order to make things easier for the parser.
tagParameters: ->
return if @tag() isnt ')'
i = 0
i = @tokens.length
loop
i += 1
tok = @prev i
return if not tok
return unless tok = @tokens[--i]
switch tok[0]
when 'IDENTIFIER' then tok[0] = 'PARAM'
when ')' then tok[0] = 'PARAM_END'
@ -389,7 +388,7 @@ exports.Lexer = class Lexer
else
for pair in delimited
[open, close] = pair
if levels.length and starts(str, close, i) and levels[levels.length - 1] is pair
if levels.length and starts(str, close, i) and last(levels) is pair
levels.pop()
i += close.length - 1
i += 1 unless levels.length
@ -469,23 +468,17 @@ exports.Lexer = class Lexer
# Peek at a tag in the current token stream.
tag: (index, newTag) ->
return unless tok = @prev index
return tok[0] = newTag if newTag?
tok[0]
return unless tok = last @tokens, index
tok[0] = newTag ? tok[0]
# Peek at a value in the current token stream.
value: (index, val) ->
return unless tok = @prev index
return tok[1] = val if val?
tok[1]
# Peek at a previous token, entire.
prev: (index) ->
@tokens[@tokens.length - (index or 1)]
return unless tok = last @tokens, index
tok[1] = val ? tok[1]
# Are we in the midst of an unfinished expression?
unfinished: ->
(prev = @prev 2 ) and prev[0] isnt '.' and
(prev = last @tokens, 1) and prev[0] isnt '.' and
(value = @value()) and NO_NEWLINE.test(value) and not CODE.test(value) and
not ASSIGNED.test(@chunk)

View File

@ -6,7 +6,7 @@
{Scope} = require './scope'
# Import the helpers we plan to use.
{compact, flatten, merge, del, include, indexOf, starts, ends} = require './helpers'
{compact, flatten, merge, del, include, indexOf, starts, ends, last} = require './helpers'
# Constant functions for nodes that don't need customization.
YES = -> yes
@ -182,11 +182,10 @@ exports.Expressions = class Expressions extends BaseNode
# An Expressions node does not return its entire body, rather it
# ensures that the final expression is returned.
makeReturn: ->
idx = @expressions.length - 1
last = @expressions[idx]
last = @expressions[idx -= 1] if last instanceof CommentNode
return this if not last or last instanceof ReturnNode
@expressions[idx] = last.makeReturn()
end = @expressions[idx = @expressions.length - 1]
end = @expressions[idx -= 1] if end instanceof CommentNode
if end and end not instanceof ReturnNode
@expressions[idx] = end.makeReturn()
this
# An **Expressions** is the only node that can serve as the root.
@ -317,10 +316,10 @@ exports.ValueNode = class ValueNode extends BaseNode
@base instanceof ObjectNode and not @hasProperties()
isSplice: ->
@hasProperties() and @properties[@properties.length - 1] instanceof SliceNode
last(@properties) instanceof SliceNode
isComplex: ->
@base.isComplex() or @properties.length
@base.isComplex() or @hasProperties()
makeReturn: ->
if @hasProperties() then super() else @base.makeReturn()
@ -380,7 +379,7 @@ exports.ValueNode = class ValueNode extends BaseNode
if prop.soakNode
if i is 0 and @base.isComplex()
temp = o.scope.freeVariable 'ref'
complete = "(#{ baseline = temp } = (#{prevcomp = complete}))"
complete = "(#{ baseline = temp } = (#{complete}))"
complete = if i is 0 and not o.scope.check complete
"(typeof #{complete} === \"undefined\" || #{baseline} === null)"
else
@ -457,7 +456,8 @@ exports.CallNode = class CallNode extends BaseNode
o.chainRoot = this unless o.chainRoot
op = @tags.operation
if @exist
if @variable instanceof ValueNode and @variable.properties[@variable.properties.length - 1] instanceof AccessorNode
if @variable instanceof ValueNode and
last(@variable.properties) instanceof AccessorNode
methodAccessor = @variable.properties.pop()
[first, meth] = @variable.compileReference o
@first = new ValueNode(first, [methodAccessor]).compile o
@ -683,7 +683,7 @@ exports.ObjectNode = class ObjectNode extends BaseNode
top = del o, 'top'
o.indent = @idt 1
nonComments = prop for prop in @properties when (prop not instanceof CommentNode)
lastNoncom = nonComments[nonComments.length - 1]
lastNoncom = last nonComments
props = for prop, i in @properties
join = ",\n"
join = "\n" if (prop is lastNoncom) or (prop instanceof CommentNode)
@ -841,11 +841,11 @@ exports.AssignNode = class AssignNode extends BaseNode
return @compileSplice(o) if @isValue() and @variable.isSplice()
stmt = del o, 'asStatement'
name = @variable.compile(o)
last = if @isValue() then @variable.last.replace(@LEADING_DOT, '') else name
end = if @isValue() then @variable.last.replace(@LEADING_DOT, '') else name
match = name.match(@PROTO_ASSIGN)
proto = match and match[1]
if @value instanceof CodeNode
@value.name = last if last.match(IDENTIFIER)
@value.name = end if IDENTIFIER.test end
@value.proto = proto if proto
val = @value.compile o
return "#{name}: #{val}" if @context is 'object'
@ -1041,20 +1041,20 @@ exports.SplatNode = class SplatNode extends BaseNode
# splats, to a proper array
@compileSplattedArray: (list, o) ->
args = []
end = -1
for arg, i in list
code = arg.compile o
prev = args[last = args.length - 1]
prev = args[end]
if arg not instanceof SplatNode
if prev and starts(prev, '[') and ends(prev, ']')
args[last] = "#{prev.slice 0, -1}, #{code}]"
args[end] = "#{prev.slice 0, -1}, #{code}]"
continue
else if prev and starts(prev, '.concat([') and ends(prev, '])')
args[last] = "#{prev.slice 0, -2}, #{code}])"
if prev and starts(prev, '.concat([') and ends(prev, '])')
args[end] = "#{prev.slice 0, -2}, #{code}])"
continue
else
code = "[#{code}]"
args.push(if i is 0 then code else ".concat(#{code})")
args.join('')
code = "[#{code}]"
args[++end] = if i is 0 then code else ".concat(#{code})"
args.join ''
#### WhileNode
@ -1470,7 +1470,7 @@ exports.SwitchNode = class SwitchNode extends BaseNode
condition = new OpNode '!!', new ParentheticalNode condition if @tags.subjectless
code += "\n#{ @idt(1) }case #{ condition.compile o }:"
code += "\n#{ block.compile o }"
code += "\n#{ idt }break;" unless exprs[exprs.length - 1] instanceof ReturnNode
code += "\n#{ idt }break;" unless last(exprs) instanceof ReturnNode
if @otherwise
code += "\n#{ @idt(1) }default:\n#{ @otherwise.compile o }"
code += "\n#{ @tab }}"

View File

@ -1,12 +1,14 @@
{indexOf, include, starts, ends, compact, count, merge, extend, flatten, del} = require '../lib/helpers'
{indexOf, include, starts, ends, compact, count, merge, extend, flatten, del, last} = require '../lib/helpers'
array = [0..4]
string = array.join ''
object = {}
# Test `indexOf`
array = [0..4]
ok indexOf(array, 0) is 0
ok indexOf(array, 2) is 2
ok indexOf(array, 4) is 4
ok indexOf(array, 6) is -1
eq 0, indexOf array, 0
eq 2, indexOf array, 2
eq 4, indexOf array, 4
eq(-1, indexOf array, 6)
# Test `include`
ok include array, 0
@ -15,8 +17,6 @@ ok include array, 4
ok not include array, 6
# Test `starts`
string = array.join ''
ok starts string, '012'
ok starts string, '34', 3
ok not starts string, '42'
@ -29,18 +29,21 @@ ok not ends string, '42'
ok not ends string, '42', 6
# Test `merge`
object = {}
merged = merge object, array
ok merged isnt object
ok merged[3] is 3
eq merged[3], 3
# Test `extend`
ok object is extend object, array
ok object[3] is 3
eq object[3], 3
# Test `flatten`
ok "#{ flatten [0, [1, 2], 3, [4]] }" is "#{ array }"
eq "#{ flatten [0, [1, 2], 3, [4]] }", "#{ array }"
ok 1 is del object, 1
# Test `del`
eq 1, del object, 1
ok 1 not of object
# Test `last`
eq 4, last array
eq 2, last array, 2