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.
- data/coffee-script.gemspec +4 -3
- data/examples/code.coffee +17 -17
- data/examples/poignant.coffee +45 -12
- data/examples/potion.coffee +11 -11
- data/examples/underscore.coffee +124 -115
- data/{lib/coffee_script → extras}/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +0 -0
- data/{lib/coffee_script → extras}/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +11 -26
- data/{lib/coffee_script → extras}/CoffeeScript.tmbundle/info.plist +0 -0
- data/extras/EXTRAS +20 -0
- data/extras/coffee.vim +111 -0
- data/lib/coffee-script.rb +1 -1
- data/lib/coffee_script/command_line.rb +6 -4
- data/lib/coffee_script/grammar.y +26 -17
- data/lib/coffee_script/lexer.rb +31 -13
- data/lib/coffee_script/narwhal/coffee-script.coffee +6 -6
- data/lib/coffee_script/narwhal/lib/coffee-script.js +1 -1
- data/lib/coffee_script/narwhal/loader.coffee +3 -3
- data/lib/coffee_script/nodes.rb +48 -32
- data/lib/coffee_script/parse_error.rb +5 -5
- data/lib/coffee_script/parser.rb +1267 -1234
- data/lib/coffee_script/rewriter.rb +80 -10
- data/package.json +1 -1
- metadata +7 -7
- data/examples/documents.coffee +0 -72
- data/examples/syntax_errors.coffee +0 -20
data/{lib/coffee_script → extras}/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences
RENAMED
File without changes
|
@@ -19,52 +19,31 @@
|
|
19
19
|
<dict>
|
20
20
|
<key>captures</key>
|
21
21
|
<dict>
|
22
|
-
|
22
|
+
<key>1</key>
|
23
23
|
<dict>
|
24
24
|
<key>name</key>
|
25
|
-
<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: => … </string>
|
45
|
-
<key>match</key>
|
46
|
-
<string>([a-zA-Z0-9_?.$:*]*?)\s*(=\b|:\b)\s*([\w,\s]*?)\s*(=+>)</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>
|
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
|
44
|
+
<string>match stuff like: a -> … </string>
|
66
45
|
<key>match</key>
|
67
|
-
<string>([a-zA-Z0-9_
|
46
|
+
<string>(\()([a-zA-Z0-9_?.$]*(,\s*[a-zA-Z0-9_?.$]+)*)(\))\s*((=|-)>)</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>(=|-)></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>!|%|&|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\?|\|\||\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
|
File without changes
|
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.
|
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
|
-
|
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
|
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(
|
164
|
+
FileUtils.cp_r("#{ROOT}/extras/CoffeeScript.tmbundle", bundle_dir)
|
163
165
|
end
|
164
166
|
|
165
167
|
# Use OptionParser for all the options.
|
data/lib/coffee_script/grammar.y
CHANGED
@@ -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
|
42
|
-
right RETURN
|
43
|
-
right '
|
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
|
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
|
-
'
|
211
|
-
| '
|
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],
|
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
|
-
|
|
251
|
+
| Slice { result = SliceNode.new(val[0]) }
|
250
252
|
;
|
251
253
|
|
252
254
|
# Indexing into an object or array.
|
253
255
|
Index:
|
254
|
-
|
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
|
-
|
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
|
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]) }
|
data/lib/coffee_script/lexer.rb
CHANGED
@@ -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?(\
|
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\
|
41
|
-
COMMENT_CLEANER = /(
|
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 =
|
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, :
|
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
|
-
|
244
|
-
|
245
|
-
tok[0] = :
|
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
|
|