From bb9fdd3015d643179c216bd3a6ef1ba0d623aeb9 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Wed, 13 Jan 2010 21:27:22 -0500 Subject: [PATCH] while loops can now be used as expressions -- they return an array containing the computed result of each iteration. --- examples/documents.coffee | 6 ++-- lib/coffee_script/grammar.y | 1 + lib/coffee_script/nodes.rb | 30 +++++++++++++++---- .../fixtures/execution/test_everything.coffee | 2 +- test/fixtures/execution/test_while.coffee | 17 +++++++++++ 5 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/execution/test_while.coffee diff --git a/examples/documents.coffee b/examples/documents.coffee index 439dd4ca..31d38d8e 100644 --- a/examples/documents.coffee +++ b/examples/documents.coffee @@ -15,8 +15,8 @@ dc.model.Document: dc.Model.extend({ # document by binding to Metadata, instead of on-the-fly. metadata: => docId: this.id - _.select(Metadata.models(), (meta => - _.any(meta.get('instances'), instance => + _.select(Metadata.models(), (meta => + _.any(meta.get('instances'), instance => instance.document_id is docId))) bookmark: pageNumber => @@ -60,7 +60,7 @@ dc.model.DocumentSet: dc.model.RESTfulSet.extend({ # change their selected state. _onModelEvent: e, model => this.base(e, model) - fire: e == dc.Model.CHANGED and model.hasChanged('selected') + fire: e is dc.Model.CHANGED and model.hasChanged('selected') if fire then _.defer(_(this.fire).bind(this, this.SELECTION_CHANGED, this)) }) diff --git a/lib/coffee_script/grammar.y b/lib/coffee_script/grammar.y index f6bf2466..ea635e96 100644 --- a/lib/coffee_script/grammar.y +++ b/lib/coffee_script/grammar.y @@ -353,6 +353,7 @@ rule While: WHILE Expression Block { result = WhileNode.new(val[1], val[2]) } | WHILE Expression { result = WhileNode.new(val[1], nil) } + | Expression WHILE Expression { result = WhileNode.new(val[2], Expressions.wrap(val[0])) } ; # Array comprehensions, including guard and current index. diff --git a/lib/coffee_script/nodes.rb b/lib/coffee_script/nodes.rb index 0772add8..acc42eb6 100644 --- a/lib/coffee_script/nodes.rb +++ b/lib/coffee_script/nodes.rb @@ -36,9 +36,9 @@ module CoffeeScript def compile(o={}) @options = o.dup @indent = o[:indent] - top = self.is_a?(ForNode) ? @options[:top] : @options.delete(:top) - closure = statement? && !statement_only? && !top && !@options[:return] - closure ? compile_closure(@options) : compile_node(@options) + top = self.top_sensitive? ? @options[:top] : @options.delete(:top) + closure = statement? && !statement_only? && !top && !@options[:return] + closure ? compile_closure(@options) : compile_node(@options) end def compile_closure(o={}) @@ -56,6 +56,7 @@ module CoffeeScript def unwrap; self; end def statement?; false; end def statement_only?; false; end + def top_sensitive?; false; end end # A collection of nodes, each one representing an expression. @@ -668,14 +669,27 @@ module CoffeeScript @condition, @body = condition, body end + def top_sensitive? + true + end + def compile_node(o) returns = o.delete(:return) + top = o.delete(:top) && !returns o[:indent] = idt(1) o[:top] = true cond = @condition.compile(o) - post = returns ? "\n#{idt}return null;" : '' - return write("#{idt}while (#{cond}) null;#{post}") if @body.nil? - write("#{idt}while (#{cond}) {\n#{@body.compile(o)}\n#{idt}}#{post}") + set = '' + if !top + rvar = o[:scope].free_variable + set = "#{idt}#{rvar} = [];\n" + @body = Expressions.wrap(CallNode.new( + ValueNode.new(LiteralNode.new(rvar), [AccessorNode.new('push')]), [@body.unwrap] + )) + end + post = returns ? "\n#{idt}return #{rvar};" : '' + return write("#{set}#{idt}while (#{cond}) null;#{post}") if @body.nil? + write("#{set}#{idt}while (#{cond}) {\n#{@body.compile(o)}\n#{idt}}#{post}") end end @@ -697,6 +711,10 @@ module CoffeeScript @name, @index = @index, @name if @object end + def top_sensitive? + true + end + def compile_node(o) top_level = o.delete(:top) && !o[:return] range = @source.is_a?(ValueNode) && @source.base.is_a?(RangeNode) && @source.properties.empty? diff --git a/test/fixtures/execution/test_everything.coffee b/test/fixtures/execution/test_everything.coffee index 87d44492..a1ae6b8f 100644 --- a/test/fixtures/execution/test_everything.coffee +++ b/test/fixtures/execution/test_everything.coffee @@ -26,4 +26,4 @@ func: => c.single: c.list[1..1][0] -print(func() == '-') +print(func() is '-') diff --git a/test/fixtures/execution/test_while.coffee b/test/fixtures/execution/test_while.coffee new file mode 100644 index 00000000..16972f1f --- /dev/null +++ b/test/fixtures/execution/test_while.coffee @@ -0,0 +1,17 @@ +i: 100 +while i -= 1 + +print(i is 0) + + +i: 5 +list: while i -= 1 + i * 2 + +print(list.join(' ') is "8 6 4 2") + + +i: 5 +list: (i * 3 while i -= 1) + +print(list.join(' ') is "12 9 6 3") \ No newline at end of file