adding splats to function definitions

This commit is contained in:
Jeremy Ashkenas 2009-12-31 17:50:12 -05:00
parent f299972713
commit 1d2bb3b2be
5 changed files with 57 additions and 10 deletions

View File

@ -39,7 +39,7 @@
<key>comment</key> <key>comment</key>
<string>match stuff like: funcName: =&gt; … </string> <string>match stuff like: funcName: =&gt; … </string>
<key>match</key> <key>match</key>
<string>([a-zA-Z0-9_?.$]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string> <string>([a-zA-Z0-9_?.$*]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string>
<key>name</key> <key>name</key>
<string>meta.function.coffee</string> <string>meta.function.coffee</string>
</dict> </dict>
@ -60,7 +60,7 @@
<key>comment</key> <key>comment</key>
<string>match stuff like: a =&gt; … </string> <string>match stuff like: a =&gt; … </string>
<key>match</key> <key>match</key>
<string>([a-zA-Z0-9_?., $]*)\s*(=&gt;)</string> <string>([a-zA-Z0-9_?., $*]*)\s*(=&gt;)</string>
<key>name</key> <key>name</key>
<string>meta.inline.function.coffee</string> <string>meta.inline.function.coffee</string>
</dict> </dict>

View File

@ -5,7 +5,7 @@ token IF ELSE UNLESS
token NUMBER STRING REGEX token NUMBER STRING REGEX
token TRUE FALSE YES NO ON OFF token TRUE FALSE YES NO ON OFF
token IDENTIFIER PROPERTY_ACCESS token IDENTIFIER PROPERTY_ACCESS
token CODE PARAM NEW RETURN token CODE PARAM SPLAT NEW RETURN
token TRY CATCH FINALLY THROW token TRY CATCH FINALLY THROW
token BREAK CONTINUE token BREAK CONTINUE
token FOR IN WHILE token FOR IN WHILE
@ -187,8 +187,13 @@ rule
# The parameters to a function definition. # The parameters to a function definition.
ParamList: ParamList:
PARAM { result = val } Param { result = val }
| ParamList "," PARAM { result = val[0] << val[2] } | ParamList "," Param { result = val[0] << val[2] }
;
Param:
PARAM
| SPLAT { result = SplatNode.new(val[0]) }
; ;
# Expressions that can be treated as values. # Expressions that can be treated as values.

View File

@ -190,17 +190,25 @@ module CoffeeScript
# A source of ambiguity in our grammar was parameter lists in function # A source of ambiguity in our grammar was parameter lists in function
# definitions (as opposed to argument lists in function calls). Tag # definitions (as opposed to argument lists in function calls). Tag
# parameter identifiers in order to avoid this. # parameter identifiers in order to avoid this. Also, parameter lists can
# make use of splats.
def tag_parameters def tag_parameters
index = 0 i = 0
loop do loop do
tok = @tokens[index -= 1] i -= 1
tok, prev = @tokens[i], @tokens[i - 1]
return if !tok return if !tok
next if tok[0] == ',' next if tok[0] == ','
return if tok[0] != :IDENTIFIER return if tok[0] != :IDENTIFIER
if prev && prev[0] == '*'
tok[0] = :SPLAT
@tokens.delete_at(i - 1)
i -= 1
else
tok[0] = :PARAM tok[0] = :PARAM
end end
end end
end
# Close up all remaining open blocks. # Close up all remaining open blocks.
def close_indentation def close_indentation

View File

@ -64,6 +64,11 @@ module CoffeeScript
self self
end end
def unshift(node)
@expressions.unshift(node)
self
end
# If this Expressions consists of a single node, pull it back out. # If this Expressions consists of a single node, pull it back out.
def unwrap def unwrap
@expressions.length == 1 ? @expressions.first : self @expressions.length == 1 ? @expressions.first : self
@ -389,7 +394,7 @@ module CoffeeScript
o[:scope].find(name) unless @variable.properties? o[:scope].find(name) unless @variable.properties?
return write(@value.compile(o)) if @value.custom_assign? return write(@value.compile(o)) if @value.custom_assign?
val = "#{name} = #{@value.compile(o)}" val = "#{name} = #{@value.compile(o)}"
write(o[:return] && !@value.custom_return? ? "return (#{val})" : val) write(o[:return] && !@value.custom_return? ? "#{o[:indent]}return (#{val})" : val)
end end
end end
@ -459,12 +464,35 @@ module CoffeeScript
o.delete(:no_wrap) o.delete(:no_wrap)
name = o.delete(:immediate_assign) name = o.delete(:immediate_assign)
@params.each {|id| o[:scope].parameter(id.to_s) } @params.each {|id| o[:scope].parameter(id.to_s) }
if @params.last.is_a?(SplatNode)
splat = @params.pop
splat.index = @params.length
@body.unshift(splat)
end
code = @body.compile(o, :code) code = @body.compile(o, :code)
name_part = name ? " #{name}" : '' name_part = name ? " #{name}" : ''
write("function#{name_part}(#{@params.join(', ')}) {\n#{code}\n#{indent}}") write("function#{name_part}(#{@params.join(', ')}) {\n#{code}\n#{indent}}")
end end
end end
# A parameter splat in a function definition.
class SplatNode < Node
attr_accessor :index
attr_reader :name
def initialize(name)
@name = name
end
def to_s
@name
end
def compile(o={})
"var #{@name} = Array.prototype.slice.call(arguments, #{@index})"
end
end
# An object literal. # An object literal.
class ObjectNode < Node class ObjectNode < Node
attr_reader :properties attr_reader :properties

View File

@ -0,0 +1,6 @@
func: first, second, *rest =>
rest.join(' ')
result: func(1, 2, 3, 4, 5)
print(result is "3 4 5")