weepy's new speedy comprehensions

This commit is contained in:
Jeremy Ashkenas 2010-01-07 20:27:26 -05:00
parent fab98a2219
commit c70b6f39b1
5 changed files with 29 additions and 92 deletions

View File

@ -51,6 +51,18 @@
__c[__b] = __a[__b];
}
});
JSLitmus.test('the new comprehensions', function() {
__c = []; __a = arr;
__d = function(num, __b) {
__c.push(num);
};
if (__a instanceof Array) {
for (__b=0; __b<__a.length; __b++) __d(__a[__b], __b);
} else {
for (__b in __a) { if (__a.hasOwnProperty(__b)) __d(__a[__b], __b); }
}
});
</script>
</body>

View File

@ -354,7 +354,7 @@ module CoffeeScript
idt = o[:indent]
@from_var, @to_var = o[:scope].free_variable, o[:scope].free_variable
from_val, to_val = @from.compile(o), @to.compile(o)
write("#{idt}#{@from_var} = #{from_val};\n#{idt}#{@to_var} = #{to_val};\n#{idt}")
write("#{@from_var} = #{from_val}; #{@to_var} = #{to_val};\n#{idt}")
end
def compile_node(o)
@ -625,38 +625,30 @@ module CoffeeScript
range = @source.is_a?(ValueNode) && @source.literal.is_a?(RangeNode) && @source.properties.empty?
source = range ? @source.literal : @source
scope = o[:scope]
name_found = scope.find(@name)
index_found = @index && scope.find(@index)
body_dent = o[:indent] + TAB
svar = scope.free_variable
ivar = range ? name : @index ? @index : scope.free_variable
rvar = scope.free_variable unless top_level
tvar = scope.free_variable
fvar = scope.free_variable
if range
body_dent = o[:indent] + TAB
var_part, pre_cond, post_cond = '', '', ''
index_var = scope.free_variable
source_part = source.compile_variables(o)
for_part = "#{index_var}=0, #{source.compile(o.merge(:index => ivar, :step => @step))}, #{index_var}++"
else
index_var = nil
body_dent = o[:indent] + TAB + TAB
source_part = "#{o[:indent]}#{svar} = #{source.compile(o)};\n#{o[:indent]}"
for_part = "#{ivar} in #{svar}"
pre_cond = "\n#{o[:indent] + TAB}if (#{svar}.hasOwnProperty(#{ivar})) {"
var_part = "\n#{body_dent}#{@name} = #{svar}[#{ivar}];"
post_cond = "\n#{o[:indent] + TAB}}"
source_part = "#{svar} = #{source.compile(o)};\n#{o[:indent]}"
for_part = "#{ivar}=0; #{ivar}<#{svar}.length; #{ivar}++"
end
body = @body
set_result = rvar ? "#{rvar} = [];\n#{o[:indent]}" : ''
set_result = rvar ? "#{o[:indent]}#{rvar} = []; " : o[:indent]
return_result = rvar || ''
temp_var = ValueNode.new(LiteralNode.new(tvar))
if top_level
body = Expressions.wrap(body)
else
body = Expressions.wrap(
AssignNode.new(temp_var, @body.unwrap),
CallNode.new(ValueNode.new(LiteralNode.new(rvar), [AccessorNode.new('push')]), [temp_var])
)
body = Expressions.wrap(CallNode.new(
ValueNode.new(LiteralNode.new(rvar), [AccessorNode.new('push')]), [@body.unwrap]
))
end
if o[:return]
return_result = "return #{return_result}" if o[:return]
@ -668,7 +660,14 @@ module CoffeeScript
return_result = "\n#{o[:indent]}#{return_result};" unless top_level
body = body.compile(o.merge(:indent => body_dent, :top => true))
write("#{source_part}#{set_result}for (#{for_part}) {#{pre_cond}#{var_part}\n#{body}#{post_cond}\n#{o[:indent]}}#{return_result}")
vars = range ? @name : "#{@name}, #{ivar}"
func = "#{fvar} = function(#{vars}) {\n#{body}\n#{o[:indent]}};\n#{o[:indent]}"
return write(set_result + source_part + func + "for (#{for_part}) #{fvar}(#{ivar});\n#{o[:indent]}#{return_result}") if range
call = "#{fvar}(#{svar}[#{ivar}], #{ivar})"
fast = "if (#{svar} instanceof Array) {\n#{o[:indent] + TAB}for (#{for_part}) #{call};\n#{o[:indent]}} else {\n#{o[:indent] + TAB}"
slow = "for (#{ivar} in #{svar}) { if (#{svar}.hasOwnProperty(#{ivar})) #{call}; }\n#{o[:indent]}}\n#{o[:indent]}#{return_result}"
write(set_result + source_part + func + fast + slow)
end
end

View File

@ -1,35 +0,0 @@
(function(){
// The cornerstone, an each implementation.
// Handles objects implementing forEach, arrays, and raw objects.
_.each = function each(obj, iterator, context) {
var __a, __b, __c, __d, __e, i, index, item, key;
index = 0;
try {
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (_.isArray(obj) || _.isArguments(obj)) {
__a = obj;
for (i in __a) {
if (__a.hasOwnProperty(i)) {
item = __a[i];
iterator.call(context, item, i, obj);
}
}
} else {
__c = _.keys(obj);
for (__d in __c) {
if (__c.hasOwnProperty(__d)) {
key = __c[__d];
iterator.call(context, obj[key], key, obj);
}
}
}
} catch (e) {
if (e !== breaker) {
throw e;
}
}
return obj;
};
})();

View File

@ -1,33 +0,0 @@
// The cornerstone, an each implementation.
// Handles objects implementing forEach, arrays, and raw objects.
_.each = function each(obj, iterator, context) {
var __a, __b, __c, __d, __e, i, index, item, key;
index = 0;
try {
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (_.isArray(obj) || _.isArguments(obj)) {
__a = obj;
for (i in __a) {
if (__a.hasOwnProperty(i)) {
item = __a[i];
iterator.call(context, item, i, obj);
}
}
} else {
__c = _.keys(obj);
for (__d in __c) {
if (__c.hasOwnProperty(__d)) {
key = __c[__d];
iterator.call(context, obj[key], key, obj);
}
}
}
} catch (e) {
if (e !== breaker) {
throw e;
}
}
return obj;
};

View File

@ -69,12 +69,6 @@ class ParserTest < Test::Unit::TestCase
assert assign.variable.literal == '_'
assert assign.value.is_a?(CodeNode)
assert assign.value.params == ['obj', 'iterator', 'context']
assert nodes.compile == File.read('test/fixtures/generation/each.js')
end
def test_no_wrap
nodes = @par.parse(File.read('test/fixtures/generation/each.coffee'))
assert nodes.compile(:no_wrap => true) == File.read('test/fixtures/generation/each_no_wrap.js')
end
end