New implementation of Rewriter#addImplicitBraces -- uses detectEnd..

This commit is contained in:
Jeremy Ashkenas 2010-08-10 21:13:30 -04:00
parent 0231f8da1b
commit d0b918e083
2 changed files with 65 additions and 97 deletions

View File

@ -47,9 +47,12 @@
if (!(token = this.tokens[i])) {
break;
}
if (!levels && condition(token, i)) {
if (levels === 0 && condition(token, i)) {
return action(token, i);
}
if (levels < 0) {
return action(token, i - 1);
}
if (include(EXPRESSION_START, token[0])) {
levels += 1;
}
@ -104,14 +107,14 @@
Rewriter.prototype.closeOpenCalls = function() {
return this.scanTokens(__bind(function(prev, token, post, i) {
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') {
condition = function(token, i) {
var _c;
return (')' === (_c = token[0]) || 'CALL_END' === _c);
};
action = function(token, i) {
return (token[0] = 'CALL_END');
};
this.detectEnd(i + 1, condition, action);
}
return 1;
@ -120,68 +123,44 @@
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') {
condition = function(token, i) {
var _c;
return (']' === (_c = token[0]) || 'INDEX_END' === _c);
};
action = function(token, i) {
return (token[0] = 'INDEX_END');
};
this.detectEnd(i + 1, condition, action);
}
return 1;
}, this));
};
Rewriter.prototype.addImplicitBraces = function() {
var closeBrackets, running, stack;
stack = [0];
running = false;
closeBrackets = __bind(function(i) {
var _c, len, size, tmp;
len = stack.length - 1;
_c = stack[len];
for (tmp = 0; (0 <= _c ? tmp < _c : tmp > _c); (0 <= _c ? tmp += 1 : tmp -= 1)) {
this.tokens.splice(i, 0, ['}', '}', this.tokens[i][2]]);
}
size = stack[len] + 1;
stack[len] = 0;
return size;
}, this);
var stack;
stack = [];
return this.scanTokens(__bind(function(prev, token, post, i) {
var _c, after, before, idx, len, open, size, tag;
tag = token[0];
len = stack.length - 1;
var action, before, condition, idx, last;
include(EXPRESSION_START, token[0]) ? stack.push((token[0] === 'INDENT' && (prev && prev[0] === '{')) ? '{' : token[0]) : null;
include(EXPRESSION_END, token[0]) ? stack.pop() : null;
last = stack[stack.length - 1];
before = this.tokens[i - 2];
after = this.tokens[i + 2];
open = stack[len] > 0;
if ((tag === 'TERMINATOR' && !((after && after[0] === ':') || (post && post[0] === '@' && this.tokens[i + 3] && this.tokens[i + 3][0] === ':'))) || (running && tag === ',' && post && (!('IDENTIFIER' === (_c = post[0]) || 'STRING' === _c || '@' === _c || 'TERMINATOR' === _c)))) {
running = false;
return closeBrackets(post && post[0] === 'OUTDENT' ? i + 1 : i);
} else if (include(EXPRESSION_START, tag)) {
stack.push(tag === '{' ? 1 : 0);
if (tag === '{' && post && post[0] === 'INDENT') {
return 2;
}
} else if (include(EXPRESSION_END, tag)) {
if (tag === 'OUTDENT' && post && post[0] === '}') {
return 1;
}
if (tag === 'OUTDENT') {
size = closeBrackets(i);
}
stack[len - 1] += stack.pop();
if (tag === '}') {
stack[len - 1] -= 1;
}
if (tag === 'OUTDENT') {
return size;
}
} else if (tag === ':' && !open) {
idx = before && before[0] === '@' ? i - 2 : i - 1;
if (token[0] === ':' && (!last || last[0] !== '{')) {
stack.push('{');
idx = before[0] === '@' ? i - 2 : i - 1;
this.tokens.splice(idx, 0, ['{', '{', token[2]]);
stack[stack.length - 1] += 1;
running = true;
condition = __bind(function(token, i) {
var _c, _d, _e, one, three, two;
_c = this.tokens.slice(i + 1, i + 4);
one = _c[0];
two = _c[1];
three = _c[2];
return ((('TERMINATOR' === (_d = token[0]) || 'OUTDENT' === _d)) && !((two && two[0] === ':') || (one && one[0] === '@' && three && three[0] === ':'))) || (token[0] === ',' && one && (!('IDENTIFIER' === (_e = one[0]) || 'STRING' === _e || '@' === _e || 'TERMINATOR' === _e || 'OUTDENT' === _e)));
}, this);
action = __bind(function(token, i) {
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
}, this);
this.detectEnd(i + 2, condition, action);
return 2;
}
return 1;

View File

@ -58,7 +58,8 @@ exports.Rewriter = class Rewriter
levels = 0
loop
break unless token = @tokens[i]
return action token, i if !levels and condition token, i
return action token, i if levels is 0 and condition token, i
return action token, i - 1 if levels < 0
levels += 1 if include EXPRESSION_START, token[0]
levels -= 1 if include EXPRESSION_END, token[0]
i += 1
@ -103,56 +104,44 @@ exports.Rewriter = class Rewriter
# its paired close.
closeOpenCalls: ->
@scanTokens (prev, token, post, i) =>
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'
if token[0] is 'CALL_START'
condition = (token, i) -> token[0] in [')', 'CALL_END']
action = (token, i) -> token[0] = 'CALL_END'
@detectEnd i + 1, condition, action
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'
if token[0] is 'INDEX_START'
condition = (token, i) -> token[0] in [']', 'INDEX_END']
action = (token, i) -> token[0] = 'INDEX_END'
@detectEnd i + 1, condition, action
return 1
# Object literals may be written with implicit braces, for simple cases.
# Insert the missing braces here, so that the parser doesn't have to.
addImplicitBraces: ->
stack = [0]
running = no
closeBrackets = (i) =>
len = stack.length - 1
for tmp in [0...stack[len]]
@tokens.splice(i, 0, ['}', '}', @tokens[i][2]])
size = stack[len] + 1
stack[len] = 0
size
stack = []
@scanTokens (prev, token, post, i) =>
tag = token[0]
len = stack.length - 1
if include EXPRESSION_START, token[0]
stack.push(if (token[0] is 'INDENT' and (prev and prev[0] is '{')) then '{' else token[0])
if include EXPRESSION_END, token[0]
stack.pop()
last = stack[stack.length - 1]
before = @tokens[i - 2]
after = @tokens[i + 2]
open = stack[len] > 0
if (tag is 'TERMINATOR' and not ((after and after[0] is ':') or (post and post[0] is '@' and @tokens[i + 3] and @tokens[i + 3][0] is ':'))) or
(running and tag is ',' and post and (post[0] not in ['IDENTIFIER', 'STRING', '@', 'TERMINATOR']))
running = no
return closeBrackets(if post and post[0] is 'OUTDENT' then i + 1 else i)
else if include EXPRESSION_START, tag
stack.push(if tag is '{' then 1 else 0)
return 2 if tag is '{' and post and post[0] is 'INDENT'
else if include EXPRESSION_END, tag
return 1 if tag is 'OUTDENT' and post and post[0] is '}'
size = closeBrackets(i) if tag is 'OUTDENT'
stack[len - 1] += stack.pop()
stack[len - 1] -= 1 if tag is '}'
return size if tag is 'OUTDENT'
else if tag is ':' and not open
idx = if before and before[0] is '@' then i - 2 else i - 1
if token[0] is ':' and (not last or last[0] isnt '{')
stack.push '{'
idx = if before[0] is '@' then i - 2 else i - 1
@tokens.splice idx, 0, ['{', '{', token[2]]
stack[stack.length - 1] += 1
running = yes
condition = (token, i) =>
[one, two, three] = @tokens.slice(i + 1, i + 4)
((token[0] in ['TERMINATOR', 'OUTDENT']) and not ((two and two[0] is ':') or (one and one[0] is '@' and three and three[0] is ':'))) or
(token[0] is ',' and one and (one[0] not in ['IDENTIFIER', 'STRING', '@', 'TERMINATOR', 'OUTDENT']))
action = (token, i) =>
@tokens.splice i, 0, ['}', '}', token[2]]
@detectEnd i + 2, condition, action
return 2
return 1