starting to cache fancy switch values -- fixing issue #171

This commit is contained in:
Jeremy Ashkenas 2010-02-17 21:23:59 -05:00
parent 8ff977dc65
commit 87e60dccf0
5 changed files with 60 additions and 21 deletions

View File

@ -355,7 +355,7 @@
// parameter identifiers in order to avoid this. Also, parameter lists can
// make use of splats.
lex.prototype.tag_parameters = function tag_parameters() {
var i, tok;
var _a, i, tok;
if (this.tag() !== ')') {
return null;
}
@ -366,11 +366,11 @@
if (!tok) {
return null;
}
if (tok[0] === 'IDENTIFIER') {
if ((_a = tok[0]) === 'IDENTIFIER') {
tok[0] = 'PARAM';
} else if (tok[0] === ')') {
} else if (_a === ')') {
tok[0] = 'PARAM_END';
} else if (tok[0] === '(') {
} else if (_a === '(') {
return (tok[0] = 'PARAM_START');
}
}

View File

@ -1216,23 +1216,34 @@
this.tags.statement = true;
return this;
},
// Rewrite a chain of IfNodes with their switch condition for equality.
// Tag a chain of IfNodes with their switch condition for equality.
rewrite_condition: function rewrite_condition(expression) {
var _a, _b, _c, cond;
this.switcher = expression;
return this;
},
// Rewrite a chain of IfNodes with their switch condition for equality.
rewrite_switch: function rewrite_switch(o) {
var _a, _b, assigner, cond, i, variable;
assigner = this.switcher;
if (!(this.switcher.unwrap() instanceof LiteralNode)) {
variable = new LiteralNode(o.scope.free_variable());
assigner = new AssignNode(variable, this.switcher);
this.switcher = variable;
}
this.condition = (function() {
if (this.multiple) {
_a = []; _b = this.condition;
for (_c = 0; _c < _b.length; _c++) {
cond = _b[_c];
_a.push(new OpNode('is', expression, cond));
for (i = 0; i < _b.length; i++) {
cond = _b[i];
_a.push(new OpNode('is', (i === 0 ? assigner : this.switcher), cond));
}
return _a;
} else {
return new OpNode('is', expression, this.condition);
return new OpNode('is', assigner, this.condition);
}
}).call(this);
if (this.is_chain()) {
this.else_body.rewrite_condition(expression);
this.else_body.rewrite_condition(this.switcher);
}
return this;
},
@ -1269,6 +1280,9 @@
// force sub-else bodies into statement form.
compile_statement: function compile_statement(o) {
var body, child, com_dent, cond_o, else_part, if_dent, if_part, prefix;
if (this.switcher) {
this.rewrite_switch(o);
}
child = del(o, 'chain_child');
cond_o = merge(o);
del(cond_o, 'returns');

View File

@ -156,22 +156,23 @@
brackets = [0];
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
if (token[0] === 'CALL_START') {
var _i;
if ((_i = token[0]) === 'CALL_START') {
parens.push(0);
} else if (token[0] === 'INDEX_START') {
} else if (_i === 'INDEX_START') {
brackets.push(0);
} else if (token[0] === '(') {
} else if (_i === '(') {
parens[parens.length - 1] += 1;
} else if (token[0] === '[') {
} else if (_i === '[') {
brackets[brackets.length - 1] += 1;
} else if (token[0] === ')') {
} else if (_i === ')') {
if (parens[parens.length - 1] === 0) {
parens.pop();
token[0] = 'CALL_END';
} else {
parens[parens.length - 1] -= 1;
}
} else if (token[0] === ']') {
} else if (_i === ']') {
if (brackets[brackets.length - 1] === 0) {
brackets.pop();
token[0] = 'INDEX_END';

View File

@ -970,13 +970,24 @@ IfNode: exports.IfNode: inherit Node, {
@tags.statement: true
this
# Rewrite a chain of IfNodes with their switch condition for equality.
# Tag a chain of IfNodes with their switch condition for equality.
rewrite_condition: (expression) ->
@switcher: expression
this
# Rewrite a chain of IfNodes with their switch condition for equality.
rewrite_switch: (o) ->
assigner: @switcher
if not (@switcher.unwrap() instanceof LiteralNode)
variable: new LiteralNode(o.scope.free_variable())
assigner: new AssignNode(variable, @switcher)
@switcher: variable
@condition: if @multiple
new OpNode('is', expression, cond) for cond in @condition
for cond, i in @condition
new OpNode('is', (if i is 0 then assigner else @switcher), cond)
else
new OpNode('is', expression, @condition)
@else_body.rewrite_condition(expression) if @is_chain()
new OpNode('is', assigner, @condition)
@else_body.rewrite_condition(@switcher) if @is_chain()
this
# Rewrite a chain of IfNodes to add a default case as the final else.
@ -1003,6 +1014,7 @@ IfNode: exports.IfNode: inherit Node, {
# Compile the IfNode as a regular if-else statement. Flattened chains
# force sub-else bodies into statement form.
compile_statement: (o) ->
@rewrite_switch(o) if @switcher
child: del o, 'chain_child'
cond_o: merge o
del cond_o, 'returns'

View File

@ -29,3 +29,15 @@ ok func(2)
ok func(6)
ok !func(3)
ok !func(8)
# Should cache the switch value, if anything fancier than a literal.
num: 5
result: switch num += 5
when 5 then false
when 15 then false
when 10 then true
else false
ok result