coffee-script 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,52 +19,31 @@
19
19
  <dict>
20
20
  <key>captures</key>
21
21
  <dict>
22
- <key>1</key>
22
+ <key>1</key>
23
23
  <dict>
24
24
  <key>name</key>
25
- <string>entity.name.function.coffee</string>
25
+ <string>variable.parameter.function.coffee</string>
26
26
  </dict>
27
27
  <key>2</key>
28
- <dict>
29
- <key>name</key>
30
- <string>keyword.operator.coffee</string>
31
- </dict>
32
- <key>3</key>
33
28
  <dict>
34
29
  <key>name</key>
35
30
  <string>variable.parameter.function.coffee</string>
36
31
  </dict>
37
32
  <key>4</key>
38
- <dict>
39
- <key>name</key>
40
- <string>storage.type.function.coffee</string>
41
- </dict>
42
- </dict>
43
- <key>comment</key>
44
- <string>match stuff like: funcName: =&gt; … </string>
45
- <key>match</key>
46
- <string>([a-zA-Z0-9_?.$:*]*?)\s*(=\b|:\b)\s*([\w,\s]*?)\s*(=+&gt;)</string>
47
- <key>name</key>
48
- <string>meta.function.coffee</string>
49
- </dict>
50
- <dict>
51
- <key>captures</key>
52
- <dict>
53
- <key>1</key>
54
33
  <dict>
55
34
  <key>name</key>
56
35
  <string>variable.parameter.function.coffee</string>
57
36
  </dict>
58
- <key>2</key>
37
+ <key>5</key>
59
38
  <dict>
60
39
  <key>name</key>
61
40
  <string>storage.type.function.coffee</string>
62
41
  </dict>
63
42
  </dict>
64
43
  <key>comment</key>
65
- <string>match stuff like: a =&gt; … </string>
44
+ <string>match stuff like: a -&gt; … </string>
66
45
  <key>match</key>
67
- <string>([a-zA-Z0-9_?., $*]*)\s*(=+&gt;)</string>
46
+ <string>(\()([a-zA-Z0-9_?.$]*(,\s*[a-zA-Z0-9_?.$]+)*)(\))\s*((=|-)&gt;)</string>
68
47
  <key>name</key>
69
48
  <string>meta.inline.function.coffee</string>
70
49
  </dict>
@@ -313,6 +292,12 @@
313
292
  <key>name</key>
314
293
  <string>keyword.other.coffee</string>
315
294
  </dict>
295
+ <dict>
296
+ <key>match</key>
297
+ <string>(=|-)&gt;</string>
298
+ <key>name</key>
299
+ <string>storage.type.function.coffee</string>
300
+ </dict>
316
301
  <dict>
317
302
  <key>match</key>
318
303
  <string>!|%|&amp;|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
data/extras/EXTRAS ADDED
@@ -0,0 +1,20 @@
1
+ This folder includes rough cuts of CoffeeScript syntax highlighters for
2
+ TextMate and Vim. Improvements to their lexing ability are always welcome.
3
+
4
+ To install the TextMate bundle, run `bin/coffee --install-bundle`, or drop it
5
+ into "~/Library/Application Support/TextMate/Bundles".
6
+
7
+ To install the Vim highlighter, copy "coffee.vim" into the "syntax" directory of
8
+ your vim72, and enable it in either of the following two ways:
9
+
10
+ * Manually, by running `:set syntax=coffee`
11
+
12
+ * Or automatically, by creating a "filetype.vim" file within "~/.vim", which
13
+ contains something along these lines:
14
+
15
+ if exists("did_load_filetypes")
16
+ finish
17
+ end
18
+ augroup filetypedetect
19
+ au! BufRead,BufNewFile *.coffee setfiletype coffee
20
+ augroup END
data/extras/coffee.vim ADDED
@@ -0,0 +1,111 @@
1
+ " Vim syntax file
2
+ " Language: CoffeeScript
3
+ " Maintainer: Jeff Olson <olson.jeffery@gmail.com>
4
+ " URL: http://github.com/olsonjeffery
5
+ " Changes: (jro) initial port from javascript
6
+ " Last Change: 2006 Jun 19
7
+ " Adaptation of javascript.vim syntax file (distro'd w/ vim72),
8
+ " maintained by Claudio Fleiner <claudio@fleiner.com>
9
+ " with updates from Scott Shattuck (ss) <ss@technicalpursuit.com>
10
+
11
+ if !exists("main_syntax")
12
+ if version < 600
13
+ syntax clear
14
+ elseif exists("b:current_syntax")
15
+ finish
16
+ endif
17
+ let main_syntax = 'coffee'
18
+ endif
19
+
20
+ syn case ignore
21
+
22
+ syn match coffeeLineComment "#.*" contains=@Spell,CoffeeCommentTodo
23
+ syn match coffeeSpecial "\\\d\d\d\|\\."
24
+ syn region coffeeStringD start=+"+ skip=+\\\\\|\\"+ end=+"\|$+ contains=coffeeSpecial,@htmlPreproc
25
+ syn region coffeeStringS start=+'+ skip=+\\\\\|\\'+ end=+'\|$+ contains=coffeeSpecial,@htmlPreproc
26
+
27
+ syn match coffeeSpecialCharacter "'\\.'"
28
+ syn match coffeeNumber "-\=\<\d\+L\=\>\|0[xX][0-9a-fA-F]\+\>"
29
+ syn region coffeeRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gi]\{0,2\}\s*$+ end=+/[gi]\{0,2\}\s*[;.,)\]}]+me=e-1 contains=@htmlPreproc oneline
30
+
31
+ syn match coffeePrototypeAccess "::"
32
+ syn match coffeeFunction "->"
33
+
34
+ syn keyword coffeeExtends extends
35
+ syn keyword coffeeConditional if else switch then
36
+ syn keyword coffeeRepeat while for in of
37
+ syn keyword coffeeBranch break continue
38
+ syn keyword coffeeOperator delete instanceof typeof
39
+ syn keyword coffeeType Array Boolean Date Function Number Object String RegExp
40
+ syn keyword coffeeStatement return with
41
+ syn keyword coffeeBoolean true false
42
+ syn keyword coffeeNull null undefined
43
+ syn keyword coffeeIdentifier arguments this var
44
+ syn keyword coffeeLabel case default
45
+ syn keyword coffeeException try catch finally throw
46
+ syn keyword coffeeMessage alert confirm prompt status
47
+ syn keyword coffeeGlobal self window top parent
48
+ syn keyword coffeeMember document event location
49
+ syn keyword coffeeDeprecated escape unescape
50
+ syn keyword coffeeReserved abstract boolean byte char class const debugger double enum export final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile
51
+
52
+ syn sync fromstart
53
+ syn sync maxlines=100
54
+
55
+ if main_syntax == "coffee"
56
+ syn sync ccomment coffeeComment
57
+ endif
58
+
59
+ " Define the default highlighting.
60
+ " For version 5.7 and earlier: only when not done already
61
+ " For version 5.8 and later: only when an item doesn't have highlighting yet
62
+ if version >= 508 || !exists("did_coffee_syn_inits")
63
+ if version < 508
64
+ let did_coffee_syn_inits = 1
65
+ command -nargs=+ HiLink hi link <args>
66
+ else
67
+ command -nargs=+ HiLink hi def link <args>
68
+ endif
69
+ HiLink coffeePrototypeAccess Keyword
70
+ HiLink coffeeExtends Keyword
71
+ HiLink coffeeLineComment Comment
72
+ HiLink coffeeSpecial Special
73
+ HiLink coffeeStringS String
74
+ HiLink coffeeStringD String
75
+ HiLink coffeeCharacter Character
76
+ HiLink coffeeSpecialCharacter coffeeSpecial
77
+ HiLink coffeeNumber coffeeValue
78
+ HiLink coffeeConditional Conditional
79
+ HiLink coffeeRepeat Repeat
80
+ HiLink coffeeBranch Conditional
81
+ HiLink coffeeOperator Operator
82
+ HiLink coffeeType Type
83
+ HiLink coffeeStatement Statement
84
+ HiLink coffeeFunction Function
85
+ HiLink coffeeBraces Function
86
+ HiLink coffeeError Error
87
+ HiLink coffeeScrParenError coffeeError
88
+ HiLink coffeeNull Keyword
89
+ HiLink coffeeBoolean Boolean
90
+ HiLink coffeeRegexpString String
91
+
92
+ HiLink coffeeIdentifier Identifier
93
+ HiLink coffeeLabel Label
94
+ HiLink coffeeException Exception
95
+ HiLink coffeeMessage Keyword
96
+ HiLink coffeeGlobal Keyword
97
+ HiLink coffeeMember Keyword
98
+ HiLink coffeeDeprecated Exception
99
+ HiLink coffeeReserved Keyword
100
+ HiLink coffeeDebug Debug
101
+ HiLink coffeeConstant Label
102
+
103
+ delcommand HiLink
104
+ endif
105
+
106
+ let b:current_syntax = "coffee"
107
+ if main_syntax == 'coffee'
108
+ unlet main_syntax
109
+ endif
110
+
111
+ " vim: ts=8
data/lib/coffee-script.rb CHANGED
@@ -10,7 +10,7 @@ require "coffee_script/parse_error"
10
10
  # Namespace for all CoffeeScript internal classes.
11
11
  module CoffeeScript
12
12
 
13
- VERSION = '0.2.6' # Keep in sync with the gemspec.
13
+ VERSION = '0.3.0' # Keep in sync with the gemspec.
14
14
 
15
15
  # Compile a script (String or IO) to JavaScript.
16
16
  def self.compile(script, options={})
@@ -25,9 +25,11 @@ Usage:
25
25
  # Seconds to pause between checks for changed source files.
26
26
  WATCH_INTERVAL = 0.5
27
27
 
28
+ # Path to the root of the CoffeeScript install.
29
+ ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
30
+
28
31
  # Command to execute in Narwhal
29
- PACKAGE = File.expand_path(File.dirname(__FILE__) + '/../..')
30
- LAUNCHER = "narwhal -p #{PACKAGE} -e 'require(\"coffee-script\").run(system.args);'"
32
+ LAUNCHER = "narwhal -p #{ROOT} -e 'require(\"coffee-script\").run(system.args);'"
31
33
 
32
34
  # Run the CommandLine off the contents of ARGV.
33
35
  def initialize
@@ -141,7 +143,7 @@ Usage:
141
143
  options[:no_wrap] = true if @options[:no_wrap]
142
144
  options[:globals] = true if @options[:globals]
143
145
  CoffeeScript.compile(script, options)
144
- rescue CoffeeScript::ParseError, SyntaxError => e
146
+ rescue CoffeeScript::ParseError => e
145
147
  STDERR.puts "#{source}: #{e.message}"
146
148
  exit(1) unless @options[:watch]
147
149
  nil
@@ -159,7 +161,7 @@ Usage:
159
161
  # Install the CoffeeScript TextMate bundle to ~/Library.
160
162
  def install_bundle
161
163
  bundle_dir = File.expand_path('~/Library/Application Support/TextMate/Bundles/')
162
- FileUtils.cp_r(File.dirname(__FILE__) + '/CoffeeScript.tmbundle', bundle_dir)
164
+ FileUtils.cp_r("#{ROOT}/extras/CoffeeScript.tmbundle", bundle_dir)
163
165
  end
164
166
 
165
167
  # Use OptionParser for all the options.
@@ -4,8 +4,9 @@ class Parser
4
4
  token IF ELSE UNLESS
5
5
  token NUMBER STRING REGEX
6
6
  token TRUE FALSE YES NO ON OFF
7
- token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS
8
- token CODE PARAM NEW RETURN
7
+ token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS SOAK_ACCESS
8
+ token CODE PARAM_START PARAM PARAM_END NEW RETURN
9
+ token CALL_START CALL_END INDEX_START INDEX_END
9
10
  token TRY CATCH FINALLY THROW
10
11
  token BREAK CONTINUE
11
12
  token FOR IN OF BY WHEN WHILE
@@ -16,13 +17,12 @@ token ARGUMENTS
16
17
  token NEWLINE
17
18
  token COMMENT
18
19
  token JS
19
- token THIS
20
20
  token INDENT OUTDENT
21
21
 
22
22
  # Declare order of operations.
23
23
  prechigh
24
24
  left '?'
25
- nonassoc UMINUS NOT '!' '!!' '~' '++' '--'
25
+ nonassoc UMINUS UPLUS NOT '!' '!!' '~' '++' '--'
26
26
  left '*' '/' '%'
27
27
  left '+' '-'
28
28
  left '<<' '>>' '>>>'
@@ -38,9 +38,9 @@ prechigh
38
38
  right WHEN LEADING_WHEN IN OF BY
39
39
  right THROW FOR NEW SUPER
40
40
  left EXTENDS
41
- left ASSIGN '||=' '&&=' '?='
42
- right RETURN
43
- right '=>' '==>' UNLESS IF ELSE WHILE
41
+ left '||=' '&&=' '?='
42
+ right ASSIGN RETURN
43
+ right '->' '=>' UNLESS IF ELSE WHILE
44
44
  preclow
45
45
 
46
46
  rule
@@ -141,6 +141,7 @@ rule
141
141
  '!' Expression { result = OpNode.new(val[0], val[1]) }
142
142
  | '!!' Expression { result = OpNode.new(val[0], val[1]) }
143
143
  | '-' Expression = UMINUS { result = OpNode.new(val[0], val[1]) }
144
+ | '+' Expression = UPLUS { result = OpNode.new(val[0], val[1]) }
144
145
  | NOT Expression { result = OpNode.new(val[0], val[1]) }
145
146
  | '~' Expression { result = OpNode.new(val[0], val[1]) }
146
147
  | '--' Expression { result = OpNode.new(val[0], val[1]) }
@@ -201,14 +202,15 @@ rule
201
202
 
202
203
  # Function definition.
203
204
  Code:
204
- ParamList FuncGlyph Block { result = CodeNode.new(val[0], val[2], val[1]) }
205
+ PARAM_START ParamList PARAM_END
206
+ FuncGlyph Block { result = CodeNode.new(val[1], val[4], val[3]) }
205
207
  | FuncGlyph Block { result = CodeNode.new([], val[1], val[0]) }
206
208
  ;
207
209
 
208
210
  # The symbols to signify functions, and bound functions.
209
211
  FuncGlyph:
210
- '=>' { result = :func }
211
- | '==>' { result = :boundfunc }
212
+ '->' { result = :func }
213
+ | '=>' { result = :boundfunc }
212
214
  ;
213
215
 
214
216
  # The parameters to a function definition.
@@ -238,20 +240,20 @@ rule
238
240
  | Range { result = ValueNode.new(val[0]) }
239
241
  | Value Accessor { result = val[0] << val[1] }
240
242
  | Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
241
- | THIS { result = ValueNode.new(ThisNode.new) }
242
243
  ;
243
244
 
244
245
  # Accessing into an object or array, through dot or index notation.
245
246
  Accessor:
246
247
  PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
247
- | PROTOTYPE_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], true) }
248
+ | PROTOTYPE_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :prototype) }
249
+ | SOAK_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :soak) }
248
250
  | Index { result = val[0] }
249
- | Range { result = SliceNode.new(val[0]) }
251
+ | Slice { result = SliceNode.new(val[0]) }
250
252
  ;
251
253
 
252
254
  # Indexing into an object or array.
253
255
  Index:
254
- "[" Expression "]" { result = IndexNode.new(val[1]) }
256
+ INDEX_START Expression INDEX_END { result = IndexNode.new(val[1]) }
255
257
  ;
256
258
 
257
259
  # An object literal.
@@ -290,13 +292,12 @@ rule
290
292
 
291
293
  # The list of arguments to a function invocation.
292
294
  Arguments:
293
- "(" ArgList ")" { result = val[1] }
294
- | "(" ArgList ")" Code { result = val[1] << val[3] }
295
+ CALL_START ArgList CALL_END { result = val[1] }
295
296
  ;
296
297
 
297
298
  # Calling super.
298
299
  Super:
299
- SUPER "(" ArgList ")" { result = CallNode.new(Value.new('super'), val[2]) }
300
+ SUPER CALL_START ArgList CALL_END { result = CallNode.new(Value.new('super'), val[2]) }
300
301
  ;
301
302
 
302
303
  # The range literal.
@@ -307,6 +308,14 @@ rule
307
308
  "." "." "." Expression "]" { result = RangeNode.new(val[1], val[5], true) }
308
309
  ;
309
310
 
311
+ # The slice literal.
312
+ Slice:
313
+ INDEX_START Expression "." "."
314
+ Expression INDEX_END { result = RangeNode.new(val[1], val[4]) }
315
+ | INDEX_START Expression "." "." "."
316
+ Expression INDEX_END { result = RangeNode.new(val[1], val[5], true) }
317
+ ;
318
+
310
319
  # The array literal.
311
320
  Array:
312
321
  "[" ArgList "]" { result = ArrayNode.new(val[1]) }
@@ -16,19 +16,18 @@ module CoffeeScript
16
16
  "delete", "instanceof", "typeof",
17
17
  "switch", "when",
18
18
  "super", "extends",
19
- "arguments",
20
- "this"]
19
+ "arguments"]
21
20
 
22
21
  # Token matching regexes.
23
22
  IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
24
23
  NUMBER = /\A(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
25
24
  STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m
26
- HEREDOC = /\A("{6}|'{6}|"{3}\n?(.*?)\n?(\s*)"{3}|'{3}\n?(.*?)\n?(\s*)'{3})/m
25
+ HEREDOC = /\A("{6}|'{6}|"{3}\n?(.*?)\n?([ \t]*)"{3}|'{3}\n?(.*?)\n?([ \t]*)'{3})/m
27
26
  JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m
28
27
  OPERATOR = /\A([+\*&|\/\-%=<>:!?]+)/
29
28
  WHITESPACE = /\A([ \t]+)/
30
29
  COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/
31
- CODE = /\A(=?=>)/
30
+ CODE = /\A((-|=)>)/
32
31
  REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
33
32
  MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/
34
33
  LAST_DENT = /\n([ \t]*)/
@@ -37,10 +36,10 @@ module CoffeeScript
37
36
  # Token cleaning regexes.
38
37
  JS_CLEANER = /(\A`|`\Z)/
39
38
  MULTILINER = /\n/
40
- STRING_NEWLINES = /\n\s*/
41
- COMMENT_CLEANER = /(^\s*#|\n\s*$)/
39
+ STRING_NEWLINES = /\n[ \t]*/
40
+ COMMENT_CLEANER = /(^[ \t]*#|\n[ \t]*$)/
42
41
  NO_NEWLINE = /\A([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)\Z/
43
- HEREDOC_INDENT = /^\s+/
42
+ HEREDOC_INDENT = /^[ \t]+/
44
43
 
45
44
  # Tokens which a regular expression will never immediately follow, but which
46
45
  # a division operator might.
@@ -48,9 +47,12 @@ module CoffeeScript
48
47
  NOT_REGEX = [
49
48
  :IDENTIFIER, :NUMBER, :REGEX, :STRING,
50
49
  ')', '++', '--', ']', '}',
51
- :FALSE, :NULL, :THIS, :TRUE
50
+ :FALSE, :NULL, :TRUE
52
51
  ]
53
52
 
53
+ # Tokens which could legitimately be invoked or indexed.
54
+ CALLABLE = [:IDENTIFIER, :SUPER, ')', ']', '}', :STRING]
55
+
54
56
  # Scan by attempting to match tokens one character at a time. Slow and steady.
55
57
  def tokenize(code)
56
58
  @code = code.chomp # Cleanup code by remove extra line breaks
@@ -59,6 +61,7 @@ module CoffeeScript
59
61
  @indent = 0 # The current indent level.
60
62
  @indents = [] # The stack of all indent levels we are currently within.
61
63
  @tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
64
+ @spaced = nil # The last value that has a space following it.
62
65
  while @i < @code.length
63
66
  @chunk = @code[@i..-1]
64
67
  extract_next_token
@@ -92,8 +95,15 @@ module CoffeeScript
92
95
  # 'if' will result in an [:IF, "if"] token.
93
96
  tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER
94
97
  tag = :LEADING_WHEN if tag == :WHEN && [:OUTDENT, :INDENT, "\n"].include?(last_tag)
95
- @tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2] && @tokens[-2][1] == '.')
96
98
  @tokens[-1][0] = :PROTOTYPE_ACCESS if tag == :IDENTIFIER && last_value == '::'
99
+ if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2] && @tokens[-2][1] == '.')
100
+ if @tokens[-2][0] == "?"
101
+ @tokens[-1][0] = :SOAK_ACCESS
102
+ @tokens.delete_at(-2)
103
+ else
104
+ @tokens[-1][0] = :PROPERTY_ACCESS
105
+ end
106
+ end
97
107
  token(tag, identifier)
98
108
  @i += identifier.length
99
109
  end
@@ -157,7 +167,7 @@ module CoffeeScript
157
167
  @line += indent.scan(MULTILINER).size
158
168
  @i += indent.size
159
169
  next_character = @chunk[MULTI_DENT, 4]
160
- no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && !last_value.match(CODE))
170
+ no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && @tokens[-2][0] != '.' && !last_value.match(CODE))
161
171
  return suppress_newlines(indent) if no_newlines
162
172
  size = indent.scan(LAST_DENT).last.last.length
163
173
  return newline_token(indent) if size == @indent
@@ -184,6 +194,7 @@ module CoffeeScript
184
194
  # Matches and consumes non-meaningful whitespace.
185
195
  def whitespace_token
186
196
  return false unless whitespace = @chunk[WHITESPACE, 1]
197
+ @spaced = last_value
187
198
  @i += whitespace.length
188
199
  end
189
200
 
@@ -208,6 +219,10 @@ module CoffeeScript
208
219
  tag_parameters if value && value.match(CODE)
209
220
  value ||= @chunk[0,1]
210
221
  tag = value.match(ASSIGNMENT) ? :ASSIGN : value
222
+ if !@spaced.equal?(last_value) && CALLABLE.include?(last_tag)
223
+ tag = :CALL_START if value == '('
224
+ tag = :INDEX_START if value == '['
225
+ end
211
226
  token(tag, value)
212
227
  @i += value.length
213
228
  end
@@ -235,14 +250,17 @@ module CoffeeScript
235
250
  # parameter identifiers in order to avoid this. Also, parameter lists can
236
251
  # make use of splats.
237
252
  def tag_parameters
253
+ return if last_tag != ')'
238
254
  i = 0
239
255
  loop do
240
256
  i -= 1
241
257
  tok = @tokens[i]
242
258
  return if !tok
243
- next if ['.', ','].include?(tok[0])
244
- return if tok[0] != :IDENTIFIER
245
- tok[0] = :PARAM
259
+ case tok[0]
260
+ when :IDENTIFIER then tok[0] = :PARAM
261
+ when ')' then tok[0] = :PARAM_END
262
+ when '(' then return tok[0] = :PARAM_START
263
+ end
246
264
  end
247
265
  end
248
266