coffee-script 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -36,3 +36,6 @@
36
36
 
37
37
  The source repository:
38
38
  git://github.com/jashkenas/coffee-script.git
39
+
40
+ To build CoffeeScript from source, install the "racc" gem and
41
+ run "rake build:parser". Then bin/coffee will work.
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'coffee-script'
3
- s.version = '0.2.1' # Keep version in sync with coffee-script.rb
4
- s.date = '2010-1-5'
3
+ s.version = '0.2.2' # Keep version in sync with coffee-script.rb
4
+ s.date = '2010-1-10'
5
5
 
6
6
  s.homepage = "http://jashkenas.github.com/coffee-script/"
7
7
  s.summary = "The CoffeeScript Compiler"
@@ -141,18 +141,18 @@ aliquam erat volutpat. Ut wisi enim ad."
141
141
 
142
142
  # Inheritance and calling super.
143
143
  Animal: =>
144
- Animal.prototype.move: meters =>
144
+ Animal::move: meters =>
145
145
  alert(this.name + " moved " + meters + "m.")
146
146
 
147
147
  Snake: name => this.name: name
148
148
  Snake extends Animal
149
- Snake.prototype.move: =>
149
+ Snake::move: =>
150
150
  alert('Slithering...')
151
151
  super(5)
152
152
 
153
153
  Horse: name => this.name: name
154
154
  Horse extends Animal
155
- Horse.prototype.move: =>
155
+ Horse::move: =>
156
156
  alert('Galloping...')
157
157
  super(45)
158
158
 
@@ -14,9 +14,9 @@
14
14
  # end
15
15
 
16
16
  LotteryTicket: {
17
- get_picks: => this.picks
18
- set_picks: nums => this.picks: nums
19
- get_purchase: => this.purchase
17
+ get_picks: => this.picks
18
+ set_picks: nums => this.picks: nums
19
+ get_purchase: => this.purchase
20
20
  set_purchase: amount => this.purchase: amount
21
21
  }
22
22
 
@@ -30,7 +30,7 @@
30
30
  breaker: if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
31
31
 
32
32
 
33
- # Create a safe reference to the Underscore object for reference below.
33
+ # Create a safe reference to the Underscore object forreference below.
34
34
  _: root._: obj => new wrapper(obj)
35
35
 
36
36
 
@@ -39,15 +39,15 @@
39
39
 
40
40
 
41
41
  # Create quick reference variables for speed access to core prototypes.
42
- slice: Array.prototype.slice
43
- unshift: Array.prototype.unshift
44
- toString: Object.prototype.toString
45
- hasOwnProperty: Object.prototype.hasOwnProperty
46
- propertyIsEnumerable: Object.prototype.propertyIsEnumerable
42
+ slice: Array::slice
43
+ unshift: Array::unshift
44
+ toString: Object::toString
45
+ hasOwnProperty: Object::hasOwnProperty
46
+ propertyIsEnumerable: Object::propertyIsEnumerable
47
47
 
48
48
 
49
49
  # Current version.
50
- _.VERSION: '0.5.3'
50
+ _.VERSION: '0.5.5'
51
51
 
52
52
 
53
53
  # ------------------------ Collection Functions: ---------------------------
@@ -60,7 +60,7 @@
60
60
  return obj.forEach(iterator, context) if obj.forEach
61
61
  if _.isArray(obj) or _.isArguments(obj)
62
62
  return iterator.call(context, obj[i], i, obj) for i in [0...obj.length]
63
- iterator.call(context, val, key, obj) for val, key in obj
63
+ iterator.call(context, val, key, obj) for key, val ino obj
64
64
  catch e
65
65
  throw e if e isnt breaker
66
66
  obj
@@ -148,7 +148,7 @@
148
148
  # based on '==='.
149
149
  _.include: obj, target =>
150
150
  return _.indexOf(obj, target) isnt -1 if _.isArray(obj)
151
- for val in obj
151
+ for key, val ino obj
152
152
  return true if val is target
153
153
  false
154
154
 
@@ -380,7 +380,7 @@
380
380
  # Retrieve the names of an object's properties.
381
381
  _.keys: obj =>
382
382
  return _.range(0, obj.length) if _.isArray(obj)
383
- key for val, key in obj
383
+ key for key, val ino obj
384
384
 
385
385
 
386
386
  # Retrieve the values of an object's properties.
@@ -395,7 +395,7 @@
395
395
 
396
396
  # Extend a given object with all of the properties in a source object.
397
397
  _.extend: destination, source =>
398
- for val, key in source
398
+ for key, val ino source
399
399
  destination[key]: val
400
400
  destination
401
401
 
@@ -564,8 +564,9 @@
564
564
  _.each(_.functions(_)) name =>
565
565
  method: _[name]
566
566
  wrapper.prototype[name]: =>
567
- unshift.call(arguments, this._wrapped)
568
- result(method.apply(_, arguments), this._chain)
567
+ args: _.toArray(arguments)
568
+ unshift.call(args, this._wrapped)
569
+ result(method.apply(_, args), this._chain)
569
570
 
570
571
 
571
572
  # Add all mutator Array functions to the wrapper.
@@ -584,10 +585,10 @@
584
585
 
585
586
 
586
587
  # Start chaining a wrapped Underscore object.
587
- wrapper.prototype.chain: =>
588
+ wrapper::chain: =>
588
589
  this._chain: true
589
590
  this
590
591
 
591
592
 
592
593
  # Extracts the result from a wrapped and chained object.
593
- wrapper.prototype.value: => this._wrapped
594
+ wrapper::value: => this._wrapped
@@ -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.1' # Keep in sync with the gemspec.
13
+ VERSION = '0.2.2' # 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={})
@@ -10,6 +10,10 @@
10
10
  </array>
11
11
  <key>name</key>
12
12
  <string>CoffeeScript</string>
13
+ <key>foldingStartMarker</key>
14
+ <string>^.*[:=] \{[^\}]*$</string>
15
+ <key>foldingStopMarker</key>
16
+ <string>\s*\}</string>
13
17
  <key>patterns</key>
14
18
  <array>
15
19
  <dict>
@@ -39,7 +43,7 @@
39
43
  <key>comment</key>
40
44
  <string>match stuff like: funcName: =&gt; … </string>
41
45
  <key>match</key>
42
- <string>([a-zA-Z0-9_?.$*]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string>
46
+ <string>([a-zA-Z0-9_?.$:*]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string>
43
47
  <key>name</key>
44
48
  <string>meta.function.coffee</string>
45
49
  </dict>
@@ -60,7 +64,7 @@
60
64
  <key>comment</key>
61
65
  <string>match stuff like: a =&gt; … </string>
62
66
  <key>match</key>
63
- <string>([a-zA-Z0-9_?., $*]*)\s*(=&gt;)</string>
67
+ <string>([a-zA-Z0-9_?., $:*]*)\s*(=&gt;)</string>
64
68
  <key>name</key>
65
69
  <string>meta.inline.function.coffee</string>
66
70
  </dict>
@@ -210,7 +214,7 @@
210
214
  </dict>
211
215
  <dict>
212
216
  <key>match</key>
213
- <string>\b([a-zA-Z$_]\w*)(\:)\s</string>
217
+ <string>\b([a-zA-Z$_](\w|\$|:)*)(\:)\s</string>
214
218
  <key>name</key>
215
219
  <string>variable.assignment.coffee</string>
216
220
  <key>captures</key>
@@ -220,7 +224,7 @@
220
224
  <key>name</key>
221
225
  <string>entity.name.function.coffee</string>
222
226
  </dict>
223
- <key>2</key>
227
+ <key>3</key>
224
228
  <dict>
225
229
  <key>name</key>
226
230
  <string>keyword.operator.coffee</string>
@@ -259,7 +263,7 @@
259
263
  </dict>
260
264
  <dict>
261
265
  <key>match</key>
262
- <string>!|\$|%|&amp;|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
266
+ <string>!|%|&amp;|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|ino|instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
263
267
  <key>name</key>
264
268
  <string>keyword.operator.coffee</string>
265
269
  </dict>
@@ -1,7 +1,13 @@
1
1
  require 'optparse'
2
2
  require 'fileutils'
3
3
  require 'open3'
4
- require File.expand_path(File.dirname(__FILE__) + '/../coffee-script')
4
+ begin
5
+ require File.expand_path(File.dirname(__FILE__) + '/../coffee-script')
6
+ rescue LoadError => e
7
+ puts(e.message)
8
+ puts("use \"rake build:parser\" to regenerate parser.rb")
9
+ exit(1)
10
+ end
5
11
 
6
12
  module CoffeeScript
7
13
 
@@ -133,6 +139,7 @@ Usage:
133
139
  begin
134
140
  options = {}
135
141
  options[:no_wrap] = true if @options[:no_wrap]
142
+ options[:globals] = true if @options[:globals]
136
143
  CoffeeScript.compile(script, options)
137
144
  rescue CoffeeScript::ParseError, SyntaxError => e
138
145
  STDERR.puts "#{source}: #{e.message}"
@@ -187,9 +194,12 @@ Usage:
187
194
  opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
188
195
  ENV['VERBOSE'] = 'true'
189
196
  end
190
- opts.on('-n', '--no-wrap', 'raw output, no safety wrapper or vars') do |n|
197
+ opts.on('-n', '--no-wrap', 'raw output, no function safety wrapper') do |n|
191
198
  @options[:no_wrap] = true
192
199
  end
200
+ opts.on('-g', '--globals', 'attach all top-level variable as globals') do |n|
201
+ @options[:globals] = true
202
+ end
193
203
  opts.on_tail('--install-bundle', 'install the CoffeeScript TextMate bundle') do |i|
194
204
  install_bundle
195
205
  exit
@@ -1,14 +1,14 @@
1
1
  class Parser
2
2
 
3
- # Declare tokens produced by the lexer
3
+ # Declare terminal tokens produced by the lexer.
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
8
- token CODE PARAM PARAM_SPLAT NEW RETURN
7
+ token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS
8
+ token CODE PARAM NEW RETURN
9
9
  token TRY CATCH FINALLY THROW
10
10
  token BREAK CONTINUE
11
- token FOR IN BY WHEN WHILE
11
+ token FOR IN INO BY WHEN WHILE
12
12
  token SWITCH LEADING_WHEN
13
13
  token DELETE INSTANCEOF TYPEOF
14
14
  token SUPER EXTENDS
@@ -21,7 +21,7 @@ token INDENT OUTDENT
21
21
  # Declare order of operations.
22
22
  prechigh
23
23
  left '?'
24
- nonassoc UMINUS PARAM_SPLAT SPLAT NOT '!' '!!' '~' '++' '--'
24
+ nonassoc UMINUS NOT '!' '!!' '~' '++' '--'
25
25
  left '*' '/' '%'
26
26
  left '+' '-'
27
27
  left '<<' '>>' '>>>'
@@ -34,11 +34,12 @@ prechigh
34
34
  left '.'
35
35
  right INDENT
36
36
  left OUTDENT
37
- right WHEN LEADING_WHEN IN BY
37
+ right WHEN LEADING_WHEN IN INO BY
38
38
  right THROW FOR NEW SUPER
39
39
  left EXTENDS
40
40
  left ASSIGN '||=' '&&='
41
- right RETURN '=>' UNLESS IF ELSE WHILE
41
+ right RETURN
42
+ right '=>' UNLESS IF ELSE WHILE
42
43
  preclow
43
44
 
44
45
  rule
@@ -58,13 +59,13 @@ rule
58
59
  | Expressions Terminator { result = val[0] }
59
60
  ;
60
61
 
61
- # All types of expressions in our language.
62
+ # All types of expressions in our language. The basic unit of CoffeeScript
63
+ # is the expression.
62
64
  Expression:
63
65
  Value
64
66
  | Call
65
67
  | Code
66
68
  | Operation
67
- | Range
68
69
  | Assign
69
70
  | If
70
71
  | Try
@@ -79,18 +80,20 @@ rule
79
80
  | Comment
80
81
  ;
81
82
 
83
+ # A block of expressions. Note that the Rewriter will convert some postfix
84
+ # forms into blocks for us, by altering the token stream.
82
85
  Block:
83
86
  INDENT Expressions OUTDENT { result = val[1] }
84
87
  | INDENT OUTDENT { result = Expressions.new }
85
88
  ;
86
89
 
87
- # All tokens that can terminate an expression.
90
+ # Tokens that can terminate an expression.
88
91
  Terminator:
89
92
  "\n"
90
93
  | ";"
91
94
  ;
92
95
 
93
- # All hard-coded values.
96
+ # All hard-coded values. These can be printed straight to JavaScript.
94
97
  Literal:
95
98
  NUMBER { result = LiteralNode.new(val[0]) }
96
99
  | STRING { result = LiteralNode.new(val[0]) }
@@ -107,12 +110,12 @@ rule
107
110
  | OFF { result = LiteralNode.new(false) }
108
111
  ;
109
112
 
110
- # Assignment to a variable.
113
+ # Assignment to a variable (or index).
111
114
  Assign:
112
115
  Value ASSIGN Expression { result = AssignNode.new(val[0], val[2]) }
113
116
  ;
114
117
 
115
- # Assignment within an object literal.
118
+ # Assignment within an object literal (can be quoted).
116
119
  AssignObj:
117
120
  IDENTIFIER ASSIGN Expression { result = AssignNode.new(ValueNode.new(val[0]), val[2], :object) }
118
121
  | STRING ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
@@ -122,6 +125,7 @@ rule
122
125
  # A return statement.
123
126
  Return:
124
127
  RETURN Expression { result = ReturnNode.new(val[1]) }
128
+ | RETURN { result = ReturnNode.new(ValueNode.new(Value.new('null'))) }
125
129
  ;
126
130
 
127
131
  # A comment.
@@ -184,8 +188,10 @@ rule
184
188
  | Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
185
189
 
186
190
  | Expression INSTANCEOF Expression { result = OpNode.new(val[1], val[0], val[2]) }
191
+ | Expression IN Expression { result = OpNode.new(val[1], val[0], val[2]) }
187
192
  ;
188
193
 
194
+ # The existence operator.
189
195
  Existence:
190
196
  Expression '?' { result = ExistenceNode.new(val[0]) }
191
197
  ;
@@ -202,13 +208,15 @@ rule
202
208
  | ParamList "," Param { result = val[0] << val[2] }
203
209
  ;
204
210
 
211
+ # A Parameter (or ParamSplat) in a function definition.
205
212
  Param:
206
213
  PARAM
207
- | PARAM_SPLAT PARAM { result = ParamSplatNode.new(val[1]) }
214
+ | PARAM "." "." "." { result = ParamSplatNode.new(val[0]) }
208
215
  ;
209
216
 
217
+ # A regular splat.
210
218
  Splat:
211
- '*' Value = SPLAT { result = ArgSplatNode.new(val[1]) }
219
+ Expression "." "." "." { result = ArgSplatNode.new(val[0])}
212
220
  ;
213
221
 
214
222
  # Expressions that can be treated as values.
@@ -218,6 +226,7 @@ rule
218
226
  | Array { result = ValueNode.new(val[0]) }
219
227
  | Object { result = ValueNode.new(val[0]) }
220
228
  | Parenthetical { result = ValueNode.new(val[0]) }
229
+ | Range { result = ValueNode.new(val[0]) }
221
230
  | Value Accessor { result = val[0] << val[1] }
222
231
  | Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
223
232
  ;
@@ -225,6 +234,7 @@ rule
225
234
  # Accessing into an object or array, through dot or index notation.
226
235
  Accessor:
227
236
  PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
237
+ | PROTOTYPE_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], true) }
228
238
  | Index { result = val[0] }
229
239
  | Range { result = SliceNode.new(val[0]) }
230
240
  ;
@@ -269,6 +279,7 @@ rule
269
279
  # | Invocation Code { result = val[0] << val[1] }
270
280
  ;
271
281
 
282
+ # The list of arguments to a function invocation.
272
283
  Arguments:
273
284
  "(" ArgList ")" { result = val[1] }
274
285
  | "(" ArgList ")" Code { result = val[1] << val[3] }
@@ -330,6 +341,7 @@ rule
330
341
  # The while loop. (there is no do..while).
331
342
  While:
332
343
  WHILE Expression Block { result = WhileNode.new(val[1], val[2]) }
344
+ | WHILE Expression { result = WhileNode.new(val[1], nil) }
333
345
  ;
334
346
 
335
347
  # Array comprehensions, including guard and current index.
@@ -349,6 +361,7 @@ rule
349
361
  # The source of the array comprehension can optionally be filtered.
350
362
  ForSource:
351
363
  IN Expression { result = {:source => val[1]} }
364
+ | INO Expression { result = {:source => val[1], :object => true} }
352
365
  | ForSource
353
366
  WHEN Expression { result = val[0].merge(:filter => val[2]) }
354
367
  | ForSource
@@ -374,12 +387,10 @@ rule
374
387
  LEADING_WHEN Expression Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
375
388
  | LEADING_WHEN Expression Block
376
389
  Terminator { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
377
- | Comment
390
+ | Comment Terminator When { result = val[2].add_comment(val[0]) }
378
391
  ;
379
392
 
380
- # All of the following nutso if-else destructuring is to make the
381
- # grammar expand unambiguously.
382
-
393
+ # The most basic form of "if".
383
394
  IfBlock:
384
395
  IF Expression Block { result = IfNode.new(val[1], val[2]) }
385
396
  ;
@@ -12,23 +12,23 @@ module CoffeeScript
12
12
  "new", "return",
13
13
  "try", "catch", "finally", "throw",
14
14
  "break", "continue",
15
- "for", "in", "by", "where", "while",
15
+ "for", "in", "ino", "by", "where", "while",
16
16
  "switch", "when",
17
17
  "super", "extends",
18
18
  "arguments",
19
19
  "delete", "instanceof", "typeof"]
20
20
 
21
21
  # Token matching regexes.
22
- IDENTIFIER = /\A([a-zA-Z$_]\w*)/
22
+ IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
23
23
  NUMBER = /\A(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
24
- STRING = /\A(""|''|"(.*?)[^\\]"|'(.*?)[^\\]')/m
25
- JS = /\A(``|`(.*?)[^\\]`)/m
24
+ STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m
25
+ JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m
26
26
  OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
27
27
  WHITESPACE = /\A([ \t]+)/
28
28
  COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/
29
29
  CODE = /\A(=>)/
30
- REGEX = /\A(\/(.*?)[^\\]\/[imgy]{0,4})/
31
- MULTI_DENT = /\A((\n([ \t]*)?)+)/
30
+ REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
31
+ MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/
32
32
  LAST_DENT = /\n([ \t]*)/
33
33
  ASSIGNMENT = /\A(:|=)\Z/
34
34
 
@@ -88,6 +88,7 @@ module CoffeeScript
88
88
  tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER
89
89
  tag = :LEADING_WHEN if tag == :WHEN && [:OUTDENT, :INDENT, "\n"].include?(last_tag)
90
90
  @tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2][1] == '.')
91
+ @tokens[-1][0] = :PROTOTYPE_ACCESS if tag == :IDENTIFIER && last_value == '::'
91
92
  token(tag, identifier)
92
93
  @i += identifier.length
93
94
  end
@@ -139,7 +140,9 @@ module CoffeeScript
139
140
  return false unless indent = @chunk[MULTI_DENT, 1]
140
141
  @line += indent.scan(MULTILINER).size
141
142
  @i += indent.size
142
- return suppress_newlines(indent) if last_value.to_s.match(NO_NEWLINE) && last_value != "=>"
143
+ next_character = @chunk[MULTI_DENT, 4]
144
+ no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && last_value != "=>")
145
+ return suppress_newlines(indent) if no_newlines
143
146
  size = indent.scan(LAST_DENT).last.last.length
144
147
  return newline_token(indent) if size == @indent
145
148
  if size > @indent
@@ -221,8 +224,7 @@ module CoffeeScript
221
224
  i -= 1
222
225
  tok = @tokens[i]
223
226
  return if !tok
224
- next if tok[0] == ','
225
- next tok[0] = :PARAM_SPLAT if tok[0] == '*'
227
+ next if ['.', ','].include?(tok[0])
226
228
  return if tok[0] != :IDENTIFIER
227
229
  tok[0] = :PARAM
228
230
  end