mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
added array comprehensions over ranges
This commit is contained in:
parent
834442148b
commit
ff78546465
5 changed files with 38 additions and 16 deletions
|
@ -3,3 +3,6 @@ lunch: food.eat() for food in ['toast', 'cheese', 'wine'].
|
|||
|
||||
# Zebra-stripe a table.
|
||||
highlight(row) for row, i in table if i % 2 is 0.
|
||||
|
||||
# Check the first one hundred combinations.
|
||||
lockpick(combinations[i]) for i in [1..100].
|
|
@ -68,6 +68,7 @@ rule
|
|||
| Call
|
||||
| Code
|
||||
| Operation
|
||||
| Range
|
||||
;
|
||||
|
||||
# We have to take extra care to convert these statements into expressions.
|
||||
|
@ -224,7 +225,7 @@ rule
|
|||
Accessor:
|
||||
PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
|
||||
| Index { result = val[0] }
|
||||
| Slice { result = val[0] }
|
||||
| Range { result = SliceNode.new(val[0]) }
|
||||
;
|
||||
|
||||
# Indexing into an object or array.
|
||||
|
@ -232,11 +233,6 @@ rule
|
|||
"[" Expression "]" { result = IndexNode.new(val[1]) }
|
||||
;
|
||||
|
||||
# Array slice literal.
|
||||
Slice:
|
||||
"[" Range "]" { result = SliceNode.new(val[1]) }
|
||||
;
|
||||
|
||||
# An object literal.
|
||||
Object:
|
||||
"{" AssignList "}" { result = ObjectNode.new(val[1]) }
|
||||
|
@ -275,8 +271,8 @@ rule
|
|||
|
||||
# The range literal.
|
||||
Range:
|
||||
Value "." "." Value { result = RangeNode.new(val[0], val[3]) }
|
||||
| Value "." "." "." Value { result = RangeNode.new(val[0], val[4], true) }
|
||||
"[" Value "." "." Value "]" { result = RangeNode.new(val[1], val[4]) }
|
||||
| "[" Value "." "." "." Value "]" { result = RangeNode.new(val[1], val[5], true) }
|
||||
;
|
||||
|
||||
# The array literal.
|
||||
|
|
|
@ -307,8 +307,8 @@ module CoffeeScript
|
|||
|
||||
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||
# or to specify a range for array comprehensions.
|
||||
# Because there's no corresponding concept in JavaScript, RangeNodes are never
|
||||
# compiled directly, just used by other nodes that accept ranges.
|
||||
# RangeNodes get expanded into the equivalent array, if not used to index
|
||||
# a slice or define an array comprehension.
|
||||
class RangeNode
|
||||
attr_reader :from, :to
|
||||
|
||||
|
@ -320,6 +320,10 @@ module CoffeeScript
|
|||
@exclusive
|
||||
end
|
||||
|
||||
def compile(o={})
|
||||
write()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# An array slice literal. Unlike JavaScript's Array#slice, the second parameter
|
||||
|
@ -526,18 +530,27 @@ module CoffeeScript
|
|||
|
||||
def compile(o={})
|
||||
o = super(o)
|
||||
range = @source.is_a?(RangeNode)
|
||||
scope = o[:scope]
|
||||
name_found = scope.find(@name)
|
||||
index_found = @index && scope.find(@index)
|
||||
svar = scope.free_variable
|
||||
ivar = scope.free_variable
|
||||
ivar = range ? name : scope.free_variable
|
||||
lvar = scope.free_variable
|
||||
rvar = scope.free_variable
|
||||
index_name = @index ? @index : nil
|
||||
source_part = "#{svar} = #{@source.compile(o)};"
|
||||
for_part = "#{ivar}=0, #{lvar}=#{svar}.length; #{ivar}<#{lvar}; #{ivar}++"
|
||||
var_part = "\n#{o[:indent] + TAB}#{@name} = #{svar}[#{ivar}];\n"
|
||||
index_part = @index ? "#{o[:indent] + TAB}#{index_name} = #{ivar};\n" : ''
|
||||
if range
|
||||
source_part = ''
|
||||
operator = @source.exclusive? ? '<' : '<='
|
||||
for_part = "#{ivar}=#{@source.from.compile(o)}, #{lvar}=#{@source.to.compile(o)}; #{ivar}#{operator}#{lvar}; #{ivar}++"
|
||||
var_part = ''
|
||||
index_part = ''
|
||||
else
|
||||
source_part = "#{svar} = #{@source.compile(o)};\n#{o[:indent]}"
|
||||
for_part = "#{ivar}=0, #{lvar}=#{svar}.length; #{ivar}<#{lvar}; #{ivar}++"
|
||||
var_part = "\n#{o[:indent] + TAB}#{@name} = #{svar}[#{ivar}];"
|
||||
index_part = @index ? "\n#{o[:indent] + TAB}#{index_name} = #{ivar};" : ''
|
||||
end
|
||||
body = @body
|
||||
suffix = ';'
|
||||
set_result = "#{rvar} = [];\n#{o[:indent]}"
|
||||
|
@ -560,7 +573,7 @@ module CoffeeScript
|
|||
return_result = "\n#{o[:indent]}#{return_result};"
|
||||
indent = o[:indent] + TAB
|
||||
body = body.compile(o.merge(:indent => indent))
|
||||
write("#{source_part}\n#{o[:indent]}#{set_result}for (#{for_part}) {#{var_part}#{index_part}#{indent}#{save_result}#{body}#{suffix}\n#{o[:indent]}}#{return_result}")
|
||||
write("#{source_part}#{set_result}for (#{for_part}) {#{var_part}#{index_part}\n#{indent}#{save_result}#{body}#{suffix}\n#{o[:indent]}}#{return_result}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
5
test/fixtures/execution/test_range_comprehension.coffee
vendored
Normal file
5
test/fixtures/execution/test_range_comprehension.coffee
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
nums: i * 3 for i in [1..3].
|
||||
|
||||
result: nums.join(', ')
|
||||
|
||||
print(result is '3, 6, 9')
|
|
@ -20,4 +20,9 @@ class ExecutionTest < Test::Unit::TestCase
|
|||
assert lint_results.match(NO_WARNINGS)
|
||||
end
|
||||
|
||||
def test_lintless_documentation
|
||||
lint_results = `bin/coffee-script -l documentation/coffee/*.coffee`
|
||||
assert lint_results.match(NO_WARNINGS)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue