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

View File

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

View File

@ -190,15 +190,23 @@ module CoffeeScript
# A source of ambiguity in our grammar was parameter lists in function
# 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
index = 0
i = 0
loop do
tok = @tokens[index -= 1]
i -= 1
tok, prev = @tokens[i], @tokens[i - 1]
return if !tok
next if tok[0] == ','
return if tok[0] != :IDENTIFIER
tok[0] = :PARAM
if prev && prev[0] == '*'
tok[0] = :SPLAT
@tokens.delete_at(i - 1)
i -= 1
else
tok[0] = :PARAM
end
end
end

View File

@ -64,6 +64,11 @@ module CoffeeScript
self
end
def unshift(node)
@expressions.unshift(node)
self
end
# If this Expressions consists of a single node, pull it back out.
def unwrap
@expressions.length == 1 ? @expressions.first : self
@ -389,7 +394,7 @@ module CoffeeScript
o[:scope].find(name) unless @variable.properties?
return write(@value.compile(o)) if @value.custom_assign?
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
@ -459,12 +464,35 @@ module CoffeeScript
o.delete(:no_wrap)
name = o.delete(:immediate_assign)
@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)
name_part = name ? " #{name}" : ''
write("function#{name_part}(#{@params.join(', ')}) {\n#{code}\n#{indent}}")
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.
class ObjectNode < Node
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")