adding steps to range comprehensions

This commit is contained in:
Jeremy Ashkenas 2010-01-01 11:54:59 -05:00
parent e30a267c9d
commit 0f81dbe913
5 changed files with 27 additions and 16 deletions

View File

@ -204,7 +204,7 @@
</dict>
<dict>
<key>match</key>
<string>\b(break|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|when|while)\b</string>
<string>\b(break|by|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|when|while)\b</string>
<key>name</key>
<string>keyword.control.coffee</string>
</dict>

View File

@ -8,7 +8,7 @@ token IDENTIFIER PROPERTY_ACCESS
token CODE PARAM NEW RETURN
token TRY CATCH FINALLY THROW
token BREAK CONTINUE
token FOR IN WHILE
token FOR IN BY WHILE
token SWITCH WHEN
token DELETE INSTANCEOF TYPEOF
token SUPER EXTENDS
@ -32,7 +32,7 @@ prechigh
left '.'
right INDENT
left OUTDENT
right WHEN IN
right WHEN IN BY
right THROW FOR WHILE NEW SUPER ELSE
left UNLESS EXTENDS IF
left ASSIGN '||=' '&&='
@ -321,8 +321,8 @@ rule
# Looks a little confusing, check nodes.rb for the arguments to ForNode.
For:
Expression FOR
ForVariables ForSource { result = ForNode.new(val[0], val[3][0], val[2][0], val[3][1], val[2][1]) }
| FOR ForVariables ForSource Block { result = ForNode.new(val[3], val[2][0], val[1][0], val[2][1], val[1][1]) }
ForVariables ForSource { result = ForNode.new(val[0], val[3], val[2][0], val[2][1]) }
| FOR ForVariables ForSource Block { result = ForNode.new(val[3], val[2], val[1][0], val[1][1]) }
;
# An array comprehension has variables for the current element and index.
@ -333,9 +333,11 @@ rule
# The source of the array comprehension can optionally be filtered.
ForSource:
IN Expression { result = [val[1]] }
| IN Expression
WHEN Expression { result = [val[1], val[3]] }
IN Expression { result = {:source => val[1]} }
| ForSource
WHEN Expression { result = val[0].merge(:filter => val[2]) }
| ForSource
BY Expression { result = val[0].merge(:step => val[2]) }
;
# Switch/When blocks.

View File

@ -12,7 +12,7 @@ module CoffeeScript
"new", "return",
"try", "catch", "finally", "throw",
"break", "continue",
"for", "in", "where", "while",
"for", "in", "by", "where", "while",
"switch", "when",
"super", "extends",
"delete", "instanceof", "typeof"]

View File

@ -360,11 +360,12 @@ module CoffeeScript
write("#{idt}#{@from_var} = #{from_val};\n#{idt}#{@to_var} = #{to_val};\n#{idt}")
end
def compile(o, idx=nil)
def compile(o, idx=nil, step=nil)
raise SyntaxError, "unexpected range literal" unless idx
vars = "#{idx}=#{@from_var}"
step = step ? step.compile(o) : '1'
compare = "(#{@from_var} <= #{@to_var} ? #{idx} #{less_operator} #{@to_var} : #{idx} #{greater_operator} #{@to_var})"
incr = "(#{@from_var} <= #{@to_var} ? #{idx} += 1 : #{idx} -= 1)"
incr = "(#{@from_var} <= #{@to_var} ? #{idx} += #{step} : #{idx} -= #{step})"
write("#{vars}; #{compare}; #{incr}")
end
@ -609,10 +610,13 @@ module CoffeeScript
custom_return
custom_assign
attr_reader :body, :source, :name, :filter, :index
attr_reader :body, :source, :name, :index, :filter, :step
def initialize(body, source, name, filter, index=nil)
@body, @source, @name, @filter, @index = body, source, name, filter, index
def initialize(body, source, name, index=nil)
@body, @name, @index = body, name, index
@source = source[:source]
@filter = source[:filter]
@step = source[:step]
end
def line_ending
@ -634,7 +638,7 @@ module CoffeeScript
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, ivar)}, #{index_var}++"
for_part = "#{index_var}=0, #{@source.compile(o, ivar, @step)}, #{index_var}++"
else
index_var = nil
body_dent = o[:indent] + TAB + TAB

View File

@ -12,4 +12,9 @@ j = 5
result: for j in [j..(j+3)]
j
print(result.join(' ') is '5 6 7 8')
print(result.join(' ') is '5 6 7 8')
# With range comprehensions, you can loop in steps.
results: x for x in [0..25] by 5
print(results.join(' ') is '0 5 10 15 20 25')