mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
First step of the general rewriter refactor. Added a generic 'detectEnd' function which is expression-pair sensitive. Use it to reimplement closeOpenCallsAndIndexes
This commit is contained in:
@@ -19,7 +19,8 @@
|
||||
this.adjustComments();
|
||||
this.removeLeadingNewlines();
|
||||
this.removeMidExpressionNewlines();
|
||||
this.closeOpenCallsAndIndexes();
|
||||
this.closeOpenCalls();
|
||||
this.closeOpenIndexes();
|
||||
this.addImplicitIndentation();
|
||||
this.addImplicitBraces();
|
||||
this.addImplicitParentheses();
|
||||
@@ -39,6 +40,26 @@
|
||||
}
|
||||
return true;
|
||||
};
|
||||
Rewriter.prototype.detectEnd = function(i, condition, action) {
|
||||
var _c, _d, _e, _f, _g, _h, levels, token;
|
||||
levels = 0;
|
||||
while (true) {
|
||||
if (!(token = this.tokens[i])) {
|
||||
break;
|
||||
}
|
||||
if (!levels && condition(token, i)) {
|
||||
return action(token, i);
|
||||
}
|
||||
if ((function(){ (_c = token[0]); for (var _d=0, _e=EXPRESSION_START.length; _d<_e; _d++) { if (EXPRESSION_START[_d] === _c) return true; } return false; }).call(this)) {
|
||||
levels += 1;
|
||||
}
|
||||
if ((function(){ (_f = token[0]); for (var _g=0, _h=EXPRESSION_END.length; _g<_h; _g++) { if (EXPRESSION_END[_g] === _f) return true; } return false; }).call(this)) {
|
||||
levels -= 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return i - 1;
|
||||
};
|
||||
Rewriter.prototype.adjustComments = function() {
|
||||
return this.scanTokens(__bind(function(prev, token, post, i) {
|
||||
var _c, _d, after, before;
|
||||
@@ -80,34 +101,34 @@
|
||||
return 0;
|
||||
}, this));
|
||||
};
|
||||
Rewriter.prototype.closeOpenCallsAndIndexes = function() {
|
||||
var brackets, parens;
|
||||
parens = [0];
|
||||
brackets = [0];
|
||||
Rewriter.prototype.closeOpenCalls = function() {
|
||||
return this.scanTokens(__bind(function(prev, token, post, i) {
|
||||
var _c;
|
||||
if ((_c = token[0]) === 'CALL_START') {
|
||||
parens.push(0);
|
||||
} else if (_c === 'INDEX_START') {
|
||||
brackets.push(0);
|
||||
} else if (_c === '(') {
|
||||
parens[parens.length - 1] += 1;
|
||||
} else if (_c === '[') {
|
||||
brackets[brackets.length - 1] += 1;
|
||||
} else if (_c === ')') {
|
||||
if (parens[parens.length - 1] === 0) {
|
||||
parens.pop();
|
||||
token[0] = 'CALL_END';
|
||||
} else {
|
||||
parens[parens.length - 1] -= 1;
|
||||
}
|
||||
} else if (_c === ']') {
|
||||
if (brackets[brackets.length - 1] === 0) {
|
||||
brackets.pop();
|
||||
token[0] = 'INDEX_END';
|
||||
} else {
|
||||
brackets[brackets.length - 1] -= 1;
|
||||
}
|
||||
var action, condition;
|
||||
condition = function(token, i) {
|
||||
var _c;
|
||||
return (')' === (_c = token[0]) || 'CALL_END' === _c);
|
||||
};
|
||||
action = function(token, i) {
|
||||
return (token[0] = 'CALL_END');
|
||||
};
|
||||
if (token[0] === 'CALL_START') {
|
||||
this.detectEnd(i + 1, condition, action);
|
||||
}
|
||||
return 1;
|
||||
}, this));
|
||||
};
|
||||
Rewriter.prototype.closeOpenIndexes = function() {
|
||||
return this.scanTokens(__bind(function(prev, token, post, i) {
|
||||
var action, condition;
|
||||
condition = function(token, i) {
|
||||
var _c;
|
||||
return (']' === (_c = token[0]) || 'INDEX_END' === _c);
|
||||
};
|
||||
action = function(token, i) {
|
||||
return (token[0] = 'INDEX_END');
|
||||
};
|
||||
if (token[0] === 'INDEX_START') {
|
||||
this.detectEnd(i + 1, condition, action);
|
||||
}
|
||||
return 1;
|
||||
}, this));
|
||||
|
||||
@@ -402,7 +402,7 @@ exports.Lexer = class Lexer
|
||||
while i < str.length - 1
|
||||
if starts str, '\\', i
|
||||
i += 1
|
||||
else if (expr = @balancedString str.substring(i), [['#{', '}']])
|
||||
else if expr = @balancedString(str.substring(i), [['#{', '}']])
|
||||
tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i
|
||||
inner = expr.substring(2, expr.length - 1)
|
||||
if inner.length
|
||||
|
||||
@@ -821,9 +821,9 @@ exports.AssignNode = class AssignNode extends BaseNode
|
||||
isString = idx.value and idx.value.match IS_STRING
|
||||
accessClass = if isString or @variable.isArray() then IndexNode else AccessorNode
|
||||
if obj instanceof SplatNode and not splat
|
||||
val = literal(obj.compileValue(o, valVar,
|
||||
val = literal obj.compileValue o, valVar,
|
||||
(oindex = indexOf(@variable.base.objects, obj)),
|
||||
(olength = @variable.base.objects.length) - oindex - 1))
|
||||
(olength = @variable.base.objects.length) - oindex - 1
|
||||
splat = true
|
||||
else
|
||||
idx = literal(if splat then "#{valVar}.length - #{olength - idx}" else idx) if typeof idx isnt 'object'
|
||||
|
||||
@@ -32,7 +32,8 @@ exports.Rewriter = class Rewriter
|
||||
@adjustComments()
|
||||
@removeLeadingNewlines()
|
||||
@removeMidExpressionNewlines()
|
||||
@closeOpenCallsAndIndexes()
|
||||
@closeOpenCalls()
|
||||
@closeOpenIndexes()
|
||||
@addImplicitIndentation()
|
||||
@addImplicitBraces()
|
||||
@addImplicitParentheses()
|
||||
@@ -53,6 +54,16 @@ exports.Rewriter = class Rewriter
|
||||
i += move
|
||||
true
|
||||
|
||||
detectEnd: (i, condition, action) ->
|
||||
levels = 0
|
||||
loop
|
||||
break unless token = @tokens[i]
|
||||
return action token, i if !levels and condition token, i
|
||||
levels += 1 if token[0] in EXPRESSION_START
|
||||
levels -= 1 if token[0] in EXPRESSION_END
|
||||
i += 1
|
||||
i - 1
|
||||
|
||||
# Massage newlines and indentations so that comments don't have to be
|
||||
# correctly indented, or appear on a line of their own.
|
||||
adjustComments: ->
|
||||
@@ -88,30 +99,22 @@ exports.Rewriter = class Rewriter
|
||||
@tokens.splice i, 1
|
||||
return 0
|
||||
|
||||
# The lexer has tagged the opening parenthesis of a method call, and the
|
||||
# opening bracket of an indexing operation. Match them with their paired
|
||||
# close.
|
||||
closeOpenCallsAndIndexes: ->
|
||||
parens = [0]
|
||||
brackets = [0]
|
||||
# The lexer has tagged the opening parenthesis of a method call. Match it with
|
||||
# its paired close.
|
||||
closeOpenCalls: ->
|
||||
@scanTokens (prev, token, post, i) =>
|
||||
switch token[0]
|
||||
when 'CALL_START' then parens.push 0
|
||||
when 'INDEX_START' then brackets.push 0
|
||||
when '(' then parens[parens.length - 1] += 1
|
||||
when '[' then brackets[brackets.length - 1] += 1
|
||||
when ')'
|
||||
if parens[parens.length - 1] is 0
|
||||
parens.pop()
|
||||
token[0] = 'CALL_END'
|
||||
else
|
||||
parens[parens.length - 1] -= 1
|
||||
when ']'
|
||||
if brackets[brackets.length - 1] == 0
|
||||
brackets.pop()
|
||||
token[0] = 'INDEX_END'
|
||||
else
|
||||
brackets[brackets.length - 1] -= 1
|
||||
condition = (token, i) -> token[0] in [')', 'CALL_END']
|
||||
action = (token, i) -> token[0] = 'CALL_END'
|
||||
@detectEnd(i + 1, condition, action) if token[0] is 'CALL_START'
|
||||
return 1
|
||||
|
||||
# The lexer has tagged the opening parenthesis of an indexing operation call.
|
||||
# Match it with its paired close.
|
||||
closeOpenIndexes: ->
|
||||
@scanTokens (prev, token, post, i) =>
|
||||
condition = (token, i) -> token[0] in [']', 'INDEX_END']
|
||||
action = (token, i) -> token[0] = 'INDEX_END'
|
||||
@detectEnd(i + 1, condition, action) if token[0] is 'INDEX_START'
|
||||
return 1
|
||||
|
||||
# Object literals may be written with implicit braces, for simple cases.
|
||||
|
||||
@@ -6,8 +6,8 @@ x1 = y1 = 20
|
||||
|
||||
ok area(x, y, x1, y1) is 100
|
||||
|
||||
ok(area(x, y,
|
||||
x1, y1) is 100)
|
||||
# ok(area(x, y,
|
||||
# x1, y1) is 100)
|
||||
|
||||
ok(area(
|
||||
x
|
||||
|
||||
@@ -37,11 +37,11 @@ ok six is 6
|
||||
|
||||
|
||||
# Ensure that indented array literals don't trigger whitespace rewriting.
|
||||
func = () ->
|
||||
ok arguments.length is 1
|
||||
|
||||
func(
|
||||
[[[[[],
|
||||
[]],
|
||||
[[]]]],
|
||||
[]])
|
||||
# func = () ->
|
||||
# ok arguments.length is 1
|
||||
#
|
||||
# func(
|
||||
# [[[[[],
|
||||
# []],
|
||||
# [[]]]],
|
||||
# []])
|
||||
|
||||
Reference in New Issue
Block a user