diff --git a/documentation/speed.html b/documentation/speed.html index e4fcdefc..e756437a 100644 --- a/documentation/speed.html +++ b/documentation/speed.html @@ -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); } + } + }); diff --git a/lib/coffee_script/nodes.rb b/lib/coffee_script/nodes.rb index 7ce3fc5b..dd79605a 100644 --- a/lib/coffee_script/nodes.rb +++ b/lib/coffee_script/nodes.rb @@ -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 diff --git a/test/fixtures/generation/each.js b/test/fixtures/generation/each.js deleted file mode 100644 index 3dfdaa3f..00000000 --- a/test/fixtures/generation/each.js +++ /dev/null @@ -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; - }; -})(); \ No newline at end of file diff --git a/test/fixtures/generation/each_no_wrap.js b/test/fixtures/generation/each_no_wrap.js deleted file mode 100644 index 40ee9e4c..00000000 --- a/test/fixtures/generation/each_no_wrap.js +++ /dev/null @@ -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; -}; \ No newline at end of file diff --git a/test/unit/test_parser.rb b/test/unit/test_parser.rb index dfcc4763..ef3feab5 100644 --- a/test/unit/test_parser.rb +++ b/test/unit/test_parser.rb @@ -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