coffee-script 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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