coffee-script 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/coffee-script.gemspec +1 -1
- data/examples/potion.coffee +205 -0
- data/examples/underscore.coffee +4 -4
- data/lib/coffee-script.rb +1 -1
- data/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +3 -3
- data/lib/coffee_script/grammar.y +3 -3
- data/lib/coffee_script/lexer.rb +1 -1
- data/lib/coffee_script/narwhal/lib/coffee-script.js +3 -7
- data/lib/coffee_script/nodes.rb +74 -66
- data/lib/coffee_script/parser.rb +2 -2
- data/lib/coffee_script/value.rb +4 -0
- data/package.json +1 -1
- metadata +2 -1
data/LICENSE
CHANGED
data/coffee-script.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'coffee-script'
|
3
|
-
s.version = '0.2.
|
3
|
+
s.version = '0.2.3' # Keep version in sync with coffee-script.rb
|
4
4
|
s.date = '2010-1-10'
|
5
5
|
|
6
6
|
s.homepage = "http://jashkenas.github.com/coffee-script/"
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# Examples from _why's Potion, the Readme and "Potion: A Short Pamphlet".
|
2
|
+
|
3
|
+
# 5 times: "Odelay!" print.
|
4
|
+
|
5
|
+
print("Odelay!") for i in [1..5]
|
6
|
+
|
7
|
+
|
8
|
+
# add = (x, y): x + y.
|
9
|
+
# add(2, 4) string print
|
10
|
+
|
11
|
+
add: x, y => x + y
|
12
|
+
print(add(2, 4))
|
13
|
+
|
14
|
+
|
15
|
+
# loop: 'quaff' print.
|
16
|
+
|
17
|
+
while true
|
18
|
+
print('quaff')
|
19
|
+
|
20
|
+
|
21
|
+
# ('cheese', 'bread', 'mayo') at (1) print
|
22
|
+
|
23
|
+
print(['cheese', 'bread', 'mayo'][1])
|
24
|
+
|
25
|
+
|
26
|
+
# (language='Potion', pointless=true) at (key='language') print
|
27
|
+
|
28
|
+
print({language: 'Potion', pointless: true}['language'])
|
29
|
+
|
30
|
+
|
31
|
+
# minus = (x, y): x - y.
|
32
|
+
# minus (y=10, x=6)
|
33
|
+
|
34
|
+
minus: x, y => x - y
|
35
|
+
minus(6, 10)
|
36
|
+
|
37
|
+
|
38
|
+
# foods = ('cheese', 'bread', 'mayo')
|
39
|
+
# foods (2)
|
40
|
+
|
41
|
+
foods: ['cheese', 'bread', 'mayo']
|
42
|
+
foods[2]
|
43
|
+
|
44
|
+
|
45
|
+
# (dog='canine', cat='feline', fox='vulpine') each (key, val):
|
46
|
+
# (key, ' is a ', val) join print.
|
47
|
+
|
48
|
+
for key, val of {dog: 'canine', cat: 'feline', fox: 'vulpine'}
|
49
|
+
print(key + ' is a ' + val)
|
50
|
+
|
51
|
+
|
52
|
+
# Person = class: /name, /age, /sex.
|
53
|
+
# Person print = ():
|
54
|
+
# ('My name is ', /name, '.') join print.
|
55
|
+
|
56
|
+
Person: =>
|
57
|
+
Person::print: =>
|
58
|
+
print('My name is ' + this.name + '.')
|
59
|
+
|
60
|
+
|
61
|
+
# p = Person ()
|
62
|
+
# p /name string print
|
63
|
+
|
64
|
+
p: new Person()
|
65
|
+
print(p.name)
|
66
|
+
|
67
|
+
|
68
|
+
# Policeman = Person class (rank): /rank = rank.
|
69
|
+
# Policeman print = ():
|
70
|
+
# ('My name is ', /name, ' and I'm a ', /rank, '.') join print.
|
71
|
+
#
|
72
|
+
# Policeman ('Constable') print
|
73
|
+
|
74
|
+
Policeman: rank => this.rank: rank
|
75
|
+
Policeman extends Person
|
76
|
+
Policeman::print: =>
|
77
|
+
print('My name is ' + this.name + " and I'm a " + this.rank + '.')
|
78
|
+
|
79
|
+
print(new Policeman('Constable'))
|
80
|
+
|
81
|
+
|
82
|
+
# app = [window (width=200, height=400)
|
83
|
+
# [para 'Welcome.', button 'OK']]
|
84
|
+
# app first name
|
85
|
+
|
86
|
+
app = {
|
87
|
+
window: {width: 200, height: 200}
|
88
|
+
para: 'Welcome.'
|
89
|
+
button: 'OK'
|
90
|
+
}
|
91
|
+
app.window
|
92
|
+
|
93
|
+
|
94
|
+
# x = 1
|
95
|
+
# y = 2
|
96
|
+
#
|
97
|
+
# x = 1, y = 2
|
98
|
+
|
99
|
+
x: 1
|
100
|
+
y: 2
|
101
|
+
|
102
|
+
x: 1; y: 2
|
103
|
+
|
104
|
+
|
105
|
+
# table = (language='Potion'
|
106
|
+
# pointless=true)
|
107
|
+
|
108
|
+
table: {
|
109
|
+
language: 'Potion'
|
110
|
+
pointless: yes
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
# # this foul business...
|
115
|
+
# String length = (): 10.
|
116
|
+
|
117
|
+
# this foul business...
|
118
|
+
String::length: => 10
|
119
|
+
|
120
|
+
|
121
|
+
# block = :
|
122
|
+
# 'potion' print.
|
123
|
+
|
124
|
+
block: =>
|
125
|
+
print('potion')
|
126
|
+
|
127
|
+
|
128
|
+
# if (age > 100): 'ancient'.
|
129
|
+
|
130
|
+
if age > 100 then 'ancient'
|
131
|
+
|
132
|
+
|
133
|
+
# author =
|
134
|
+
# if (title == 'Jonathan Strange & Mr. Norrell'):
|
135
|
+
# 'Susanna Clarke'.
|
136
|
+
# elsif (title == 'The Star Diaries'):
|
137
|
+
# 'Stanislaw Lem'.
|
138
|
+
# elsif (title == 'The Slynx'):
|
139
|
+
# 'Tatyana Tolstaya'.
|
140
|
+
# else:
|
141
|
+
# '... probably Philip K. Dick'.
|
142
|
+
|
143
|
+
switch author
|
144
|
+
when 'Jonathan Strange & Mr. Norrell'
|
145
|
+
'Susanna Clarke'
|
146
|
+
when 'The Star Diaries'
|
147
|
+
'Stanislaw Lem'
|
148
|
+
when 'The Slynx'
|
149
|
+
'Tatyana Tolstaya'
|
150
|
+
else
|
151
|
+
'... probably Philip K. Dick'
|
152
|
+
|
153
|
+
|
154
|
+
# count = 8
|
155
|
+
# while (count > 0):
|
156
|
+
# 'quaff' print
|
157
|
+
# count--.
|
158
|
+
|
159
|
+
count: 8
|
160
|
+
while count > 0
|
161
|
+
print('quaff')
|
162
|
+
count--
|
163
|
+
|
164
|
+
|
165
|
+
# 1 to 5 (a):
|
166
|
+
# a string print.
|
167
|
+
|
168
|
+
print(a) for a in [1..5]
|
169
|
+
|
170
|
+
|
171
|
+
# if (3 ?gender):
|
172
|
+
# "Huh? Numbers are sexed? That's amazing." print.
|
173
|
+
|
174
|
+
if (3).gender?
|
175
|
+
print("Huh? Numbers are sexed? That's amazing.")
|
176
|
+
|
177
|
+
|
178
|
+
# HomePage get = (url):
|
179
|
+
# session = url query ? at ('session').
|
180
|
+
|
181
|
+
HomePage::get: url =>
|
182
|
+
session: url.query.session if url.query?
|
183
|
+
|
184
|
+
|
185
|
+
# BTree = class: /left, /right.
|
186
|
+
# b = BTree ()
|
187
|
+
# b /left = BTree ()
|
188
|
+
# b /right = BTree ()
|
189
|
+
|
190
|
+
BTree: =>
|
191
|
+
b: new BTree()
|
192
|
+
b.left: new BTree()
|
193
|
+
b.right: new BTree()
|
194
|
+
|
195
|
+
|
196
|
+
# BTree = class: /left, /right.
|
197
|
+
# b = BTree ()
|
198
|
+
#
|
199
|
+
# if (b ? /left):
|
200
|
+
# 'left path found!' print.
|
201
|
+
|
202
|
+
BTree: =>
|
203
|
+
b: new BTree()
|
204
|
+
|
205
|
+
print('left path found!') if b.left?
|
data/examples/underscore.coffee
CHANGED
@@ -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 key, val
|
63
|
+
iterator.call(context, val, key, obj) for key, val of 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 key, val
|
151
|
+
for key, val of 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 key, val
|
383
|
+
key for key, val of 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 key, val
|
398
|
+
for key, val of source
|
399
399
|
destination[key]: val
|
400
400
|
destination
|
401
401
|
|
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.
|
13
|
+
VERSION = '0.2.3' # 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={})
|
@@ -208,13 +208,13 @@
|
|
208
208
|
</dict>
|
209
209
|
<dict>
|
210
210
|
<key>match</key>
|
211
|
-
<string>\b(break|by|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|when|while)\b</string>
|
211
|
+
<string>\b(break|by|catch|continue|else|finally|for|in|of|if|return|switch|then|throw|try|unless|when|while)\b</string>
|
212
212
|
<key>name</key>
|
213
213
|
<string>keyword.control.coffee</string>
|
214
214
|
</dict>
|
215
215
|
<dict>
|
216
216
|
<key>match</key>
|
217
|
-
<string>\b([a-zA-Z$_](\w
|
217
|
+
<string>\b([a-zA-Z$_](\w|\$|:|\.)*)(\:)\s</string>
|
218
218
|
<key>name</key>
|
219
219
|
<string>variable.assignment.coffee</string>
|
220
220
|
<key>captures</key>
|
@@ -263,7 +263,7 @@
|
|
263
263
|
</dict>
|
264
264
|
<dict>
|
265
265
|
<key>match</key>
|
266
|
-
<string>!|%|&|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\?|\|\||\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(
|
266
|
+
<string>!|%|&|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\?|\|\||\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
|
267
267
|
<key>name</key>
|
268
268
|
<string>keyword.operator.coffee</string>
|
269
269
|
</dict>
|
data/lib/coffee_script/grammar.y
CHANGED
@@ -8,7 +8,7 @@ token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS
|
|
8
8
|
token CODE PARAM NEW RETURN
|
9
9
|
token TRY CATCH FINALLY THROW
|
10
10
|
token BREAK CONTINUE
|
11
|
-
token FOR IN
|
11
|
+
token FOR IN OF BY WHEN WHILE
|
12
12
|
token SWITCH LEADING_WHEN
|
13
13
|
token DELETE INSTANCEOF TYPEOF
|
14
14
|
token SUPER EXTENDS
|
@@ -34,7 +34,7 @@ prechigh
|
|
34
34
|
left '.'
|
35
35
|
right INDENT
|
36
36
|
left OUTDENT
|
37
|
-
right WHEN LEADING_WHEN IN
|
37
|
+
right WHEN LEADING_WHEN IN OF BY
|
38
38
|
right THROW FOR NEW SUPER
|
39
39
|
left EXTENDS
|
40
40
|
left ASSIGN '||=' '&&='
|
@@ -361,7 +361,7 @@ rule
|
|
361
361
|
# The source of the array comprehension can optionally be filtered.
|
362
362
|
ForSource:
|
363
363
|
IN Expression { result = {:source => val[1]} }
|
364
|
-
|
|
364
|
+
| OF Expression { result = {:source => val[1], :object => true} }
|
365
365
|
| ForSource
|
366
366
|
WHEN Expression { result = val[0].merge(:filter => val[2]) }
|
367
367
|
| ForSource
|
data/lib/coffee_script/lexer.rb
CHANGED
@@ -20,17 +20,13 @@
|
|
20
20
|
// Run a simple REPL, round-tripping to the CoffeeScript compiler for every
|
21
21
|
// command.
|
22
22
|
exports.run = function run(args) {
|
23
|
-
var __a,
|
23
|
+
var __a, i, path, result;
|
24
24
|
if (args.length) {
|
25
25
|
__a = args;
|
26
|
-
|
26
|
+
for (i=0; i<__a.length; i++) {
|
27
|
+
path = __a[i];
|
27
28
|
exports.evalCS(File.read(path));
|
28
29
|
delete args[i];
|
29
|
-
};
|
30
|
-
if (__a instanceof Array) {
|
31
|
-
for (i=0; i<__a.length; i++) __b(__a[i], i);
|
32
|
-
} else {
|
33
|
-
for (i in __a) { if (__a.hasOwnProperty(i)) __b(__a[i], i); }
|
34
30
|
}
|
35
31
|
return true;
|
36
32
|
}
|
data/lib/coffee_script/nodes.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
module CoffeeScript
|
2
2
|
|
3
3
|
# The abstract base class for all CoffeeScript nodes.
|
4
|
+
# All nodes are implement a "compile_node" method, which performs the
|
5
|
+
# code generation for that node. To compile a node, call the "compile"
|
6
|
+
# method, which wraps "compile_node" in some extra smarts, to know when the
|
7
|
+
# generated code should be wrapped up in a closure. An options hash is passed
|
8
|
+
# and cloned throughout, containing messages from higher in the AST,
|
9
|
+
# information about the current scope, and indentation level.
|
4
10
|
class Node
|
5
11
|
# Tabs are two spaces for pretty-printing.
|
6
12
|
TAB = ' '
|
@@ -41,7 +47,7 @@ module CoffeeScript
|
|
41
47
|
"(function() {\n#{compile_node(o.merge(:return => true))}\n#{indent}})()"
|
42
48
|
end
|
43
49
|
|
44
|
-
# Quick method for the current indentation level, plus
|
50
|
+
# Quick short method for the current indentation level, plus tabbing in.
|
45
51
|
def idt(tabs=0)
|
46
52
|
@indent + (TAB * tabs)
|
47
53
|
end
|
@@ -57,7 +63,8 @@ module CoffeeScript
|
|
57
63
|
statement
|
58
64
|
attr_reader :expressions
|
59
65
|
|
60
|
-
|
66
|
+
TRAILING_WHITESPACE = /\s+$/
|
67
|
+
UPPERCASE = /[A-Z]/
|
61
68
|
|
62
69
|
# Wrap up a node as an Expressions, unless it already is.
|
63
70
|
def self.wrap(*nodes)
|
@@ -69,12 +76,13 @@ module CoffeeScript
|
|
69
76
|
@expressions = nodes.flatten
|
70
77
|
end
|
71
78
|
|
72
|
-
# Tack an expression
|
79
|
+
# Tack an expression on to the end of this expression list.
|
73
80
|
def <<(node)
|
74
81
|
@expressions << node
|
75
82
|
self
|
76
83
|
end
|
77
84
|
|
85
|
+
# Tack an expression on to the beginning of this expression list.
|
78
86
|
def unshift(node)
|
79
87
|
@expressions.unshift(node)
|
80
88
|
self
|
@@ -91,36 +99,19 @@ module CoffeeScript
|
|
91
99
|
node == @expressions[@last_index]
|
92
100
|
end
|
93
101
|
|
102
|
+
# Determine if this is the expressions body within a constructor function.
|
103
|
+
# Constructors are capitalized by CoffeeScript convention.
|
104
|
+
def constructor?(o)
|
105
|
+
o[:top] && o[:last_assign] && o[:last_assign][0..0][UPPERCASE]
|
106
|
+
end
|
107
|
+
|
94
108
|
def compile(o={})
|
95
109
|
o[:scope] ? super(o) : compile_root(o)
|
96
110
|
end
|
97
111
|
|
98
|
-
#
|
99
|
-
# inner statements. Variables first defined within the Expressions body
|
100
|
-
# have their declarations pushed up top of the closest scope.
|
112
|
+
# Compile each expression in the Expressions body.
|
101
113
|
def compile_node(options={})
|
102
|
-
|
103
|
-
o = options.dup
|
104
|
-
@indent = o[:indent]
|
105
|
-
returns = o.delete(:return)
|
106
|
-
if last?(node) && returns && !node.statement_only?
|
107
|
-
if node.statement?
|
108
|
-
node.compile(o.merge(:return => true))
|
109
|
-
else
|
110
|
-
if o[:top] && o[:last_assign] && o[:last_assign][0..0][/[A-Z]/]
|
111
|
-
temp = o[:scope].free_variable
|
112
|
-
"#{idt}#{temp} = #{node.compile(o)};\n#{idt}return #{o[:last_assign]} === this.constructor ? this : #{temp};"
|
113
|
-
else
|
114
|
-
"#{idt}return #{node.compile(o)};"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
else
|
118
|
-
ending = node.statement? ? '' : ';'
|
119
|
-
indent = node.statement? ? '' : idt
|
120
|
-
"#{indent}#{node.compile(o.merge(:top => true))}#{ending}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
write(compiled.join("\n"))
|
114
|
+
write(@expressions.map {|n| compile_expression(n, options.dup) }.join("\n"))
|
124
115
|
end
|
125
116
|
|
126
117
|
# If this is the top-level Expressions, wrap everything in a safety closure.
|
@@ -129,15 +120,33 @@ module CoffeeScript
|
|
129
120
|
@indent = indent
|
130
121
|
o.merge!(:indent => indent, :scope => Scope.new(nil, self))
|
131
122
|
code = o[:globals] ? compile_node(o) : compile_with_declarations(o)
|
132
|
-
code.gsub!(
|
133
|
-
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
|
123
|
+
code.gsub!(TRAILING_WHITESPACE, '')
|
124
|
+
write(o[:no_wrap] ? code : "(function(){\n#{code}\n})();")
|
134
125
|
end
|
135
126
|
|
127
|
+
# Compile the expressions body, with declarations of all inner variables
|
128
|
+
# at the top.
|
136
129
|
def compile_with_declarations(o={})
|
137
130
|
code = compile_node(o)
|
138
|
-
|
139
|
-
|
140
|
-
|
131
|
+
return code unless o[:scope].declarations?(self)
|
132
|
+
write("#{idt}var #{o[:scope].declared_variables.join(', ')};\n#{code}")
|
133
|
+
end
|
134
|
+
|
135
|
+
# Compiles a single expression within the expression list.
|
136
|
+
def compile_expression(node, o)
|
137
|
+
@indent = o[:indent]
|
138
|
+
stmt = node.statement?
|
139
|
+
# We need to return the result if this is the last node in the expressions body.
|
140
|
+
returns = o.delete(:return) && last?(node) && !node.statement_only?
|
141
|
+
# Return the regular compile of the node, unless we need to return the result.
|
142
|
+
return "#{stmt ? '' : idt}#{node.compile(o.merge(:top => true))}#{stmt ? '' : ';'}" unless returns
|
143
|
+
# If it's a statement, the node knows how to return itself.
|
144
|
+
return node.compile(o.merge(:return => true)) if node.statement?
|
145
|
+
# If it's not part of a constructor, we can just return the value of the expression.
|
146
|
+
return "#{idt}return #{node.compile(o)};" unless constructor?(o)
|
147
|
+
# It's the last line of a constructor, add a safety check.
|
148
|
+
temp = o[:scope].free_variable
|
149
|
+
"#{idt}#{temp} = #{node.compile(o)};\n#{idt}return #{o[:last_assign]} === this.constructor ? this : #{temp};"
|
141
150
|
end
|
142
151
|
|
143
152
|
end
|
@@ -145,14 +154,18 @@ module CoffeeScript
|
|
145
154
|
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
146
155
|
# true, false, nil, etc.
|
147
156
|
class LiteralNode < Node
|
157
|
+
|
158
|
+
# Values of a literal node that much be treated as a statement -- no
|
159
|
+
# sense returning or assigning them.
|
148
160
|
STATEMENTS = ['break', 'continue']
|
149
161
|
|
150
|
-
|
151
|
-
|
152
|
-
|
162
|
+
# If we get handed a literal reference to an arguments object, convert
|
163
|
+
# it to an array.
|
164
|
+
ARG_ARRAY = 'Array.prototype.slice.call(arguments, 0)'
|
153
165
|
|
154
166
|
attr_reader :value
|
155
167
|
|
168
|
+
# Wrap up a compiler-generated string as a LiteralNode.
|
156
169
|
def self.wrap(string)
|
157
170
|
self.new(Value.new(string))
|
158
171
|
end
|
@@ -167,14 +180,14 @@ module CoffeeScript
|
|
167
180
|
alias_method :statement_only?, :statement?
|
168
181
|
|
169
182
|
def compile_node(o)
|
170
|
-
|
183
|
+
@value = ARG_ARRAY if @value.to_s.to_sym == :arguments
|
171
184
|
indent = statement? ? idt : ''
|
172
185
|
ending = statement? ? ';' : ''
|
173
|
-
write
|
186
|
+
write "#{indent}#{@value}#{ending}"
|
174
187
|
end
|
175
188
|
end
|
176
189
|
|
177
|
-
#
|
190
|
+
# Return an expression, or wrap it in a closure and return it.
|
178
191
|
class ReturnNode < Node
|
179
192
|
statement_only
|
180
193
|
|
@@ -202,8 +215,7 @@ module CoffeeScript
|
|
202
215
|
|
203
216
|
def compile_node(o={})
|
204
217
|
delimiter = "\n#{idt}//"
|
205
|
-
|
206
|
-
write(comment)
|
218
|
+
write("#{delimiter}#{@lines.join(delimiter)}")
|
207
219
|
end
|
208
220
|
|
209
221
|
end
|
@@ -238,6 +250,7 @@ module CoffeeScript
|
|
238
250
|
@arguments << argument
|
239
251
|
end
|
240
252
|
|
253
|
+
# Compile a vanilla function call.
|
241
254
|
def compile_node(o)
|
242
255
|
return write(compile_splat(o)) if splat?
|
243
256
|
args = @arguments.map{|a| a.compile(o) }.join(', ')
|
@@ -245,6 +258,7 @@ module CoffeeScript
|
|
245
258
|
write("#{prefix}#{@variable.compile(o)}(#{args})")
|
246
259
|
end
|
247
260
|
|
261
|
+
# Compile a call against the superclass's implementation of the current function.
|
248
262
|
def compile_super(args, o)
|
249
263
|
methname = o[:last_assign]
|
250
264
|
arg_part = args.empty? ? '' : ", #{args}"
|
@@ -253,6 +267,7 @@ module CoffeeScript
|
|
253
267
|
"#{meth}.call(this#{arg_part})"
|
254
268
|
end
|
255
269
|
|
270
|
+
# Compile a function call being passed variable arguments.
|
256
271
|
def compile_splat(o)
|
257
272
|
meth = @variable.compile(o)
|
258
273
|
obj = @variable.source || 'this'
|
@@ -275,6 +290,7 @@ module CoffeeScript
|
|
275
290
|
@sub_object, @super_object = sub_object, super_object
|
276
291
|
end
|
277
292
|
|
293
|
+
# Hooking one constructor into another's prototype chain.
|
278
294
|
def compile_node(o={})
|
279
295
|
constructor = o[:scope].free_variable
|
280
296
|
sub, sup = @sub_object.compile(o), @super_object.compile(o)
|
@@ -289,10 +305,10 @@ module CoffeeScript
|
|
289
305
|
|
290
306
|
# A value, indexed or dotted into, or vanilla.
|
291
307
|
class ValueNode < Node
|
292
|
-
attr_reader :
|
308
|
+
attr_reader :base, :properties, :last, :source
|
293
309
|
|
294
|
-
def initialize(
|
295
|
-
@
|
310
|
+
def initialize(base, properties=[])
|
311
|
+
@base, @properties = base, properties
|
296
312
|
end
|
297
313
|
|
298
314
|
def <<(other)
|
@@ -304,23 +320,23 @@ module CoffeeScript
|
|
304
320
|
return !@properties.empty?
|
305
321
|
end
|
306
322
|
|
323
|
+
# Values are statements if their base is a statement.
|
307
324
|
def statement?
|
308
|
-
@
|
325
|
+
@base.is_a?(Node) && @base.statement? && !properties?
|
309
326
|
end
|
310
327
|
|
311
328
|
def compile_node(o)
|
312
329
|
only = o.delete(:only_first)
|
313
330
|
props = only ? @properties[0...-1] : @properties
|
314
|
-
parts = [@
|
315
|
-
val.respond_to?(:compile) ? val.compile(o) : val.to_s
|
316
|
-
end
|
331
|
+
parts = [@base, props].flatten.map {|val| val.compile(o) }
|
317
332
|
@last = parts.last
|
318
333
|
@source = parts.length > 1 ? parts[0...-1].join('') : nil
|
319
334
|
write(parts.join(''))
|
320
335
|
end
|
321
336
|
end
|
322
337
|
|
323
|
-
# A dotted accessor into a part of a value
|
338
|
+
# A dotted accessor into a part of a value, or the :: shorthand for
|
339
|
+
# an accessor into the object's prototype.
|
324
340
|
class AccessorNode < Node
|
325
341
|
attr_reader :name
|
326
342
|
|
@@ -360,14 +376,6 @@ module CoffeeScript
|
|
360
376
|
@exclusive
|
361
377
|
end
|
362
378
|
|
363
|
-
def less_operator
|
364
|
-
@exclusive ? '<' : '<='
|
365
|
-
end
|
366
|
-
|
367
|
-
def greater_operator
|
368
|
-
@exclusive ? '>' : '>='
|
369
|
-
end
|
370
|
-
|
371
379
|
def compile_variables(o)
|
372
380
|
@indent = o[:indent]
|
373
381
|
@from_var, @to_var = o[:scope].free_variable, o[:scope].free_variable
|
@@ -376,12 +384,13 @@ module CoffeeScript
|
|
376
384
|
end
|
377
385
|
|
378
386
|
def compile_node(o)
|
387
|
+
return compile_array(o) unless o[:index]
|
379
388
|
idx, step = o.delete(:index), o.delete(:step)
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
compare
|
384
|
-
incr
|
389
|
+
vars = "#{idx}=#{@from_var}"
|
390
|
+
step = step ? step.compile(o) : '1'
|
391
|
+
equals = @exclusive ? '' : '='
|
392
|
+
compare = "(#{@from_var} <= #{@to_var} ? #{idx} <#{equals} #{@to_var} : #{idx} >#{equals} #{@to_var})"
|
393
|
+
incr = "(#{@from_var} <= #{@to_var} ? #{idx} += #{step} : #{idx} -= #{step})"
|
385
394
|
write("#{vars}; #{compare}; #{incr}")
|
386
395
|
end
|
387
396
|
|
@@ -640,8 +649,8 @@ module CoffeeScript
|
|
640
649
|
|
641
650
|
def compile_node(o)
|
642
651
|
top_level = o.delete(:top) && !o[:return]
|
643
|
-
range = @source.is_a?(ValueNode) && @source.
|
644
|
-
source = range ? @source.
|
652
|
+
range = @source.is_a?(ValueNode) && @source.base.is_a?(RangeNode) && @source.properties.empty?
|
653
|
+
source = range ? @source.base : @source
|
645
654
|
scope = o[:scope]
|
646
655
|
name_found = @name && scope.find(@name)
|
647
656
|
index_found = @index && scope.find(@index)
|
@@ -657,8 +666,7 @@ module CoffeeScript
|
|
657
666
|
else
|
658
667
|
index_var = nil
|
659
668
|
source_part = "#{svar} = #{source.compile(o)};\n#{idt}"
|
660
|
-
for_part = "#{ivar}=0; #{ivar}<#{svar}.length; #{ivar}++"
|
661
|
-
for_part = "#{ivar} in #{svar}" if @object
|
669
|
+
for_part = @object ? "#{ivar} in #{svar}" : "#{ivar}=0; #{ivar}<#{svar}.length; #{ivar}++"
|
662
670
|
var_part = @name ? "#{body_dent}#{@name} = #{svar}[#{ivar}];\n" : ''
|
663
671
|
end
|
664
672
|
body = @body
|
data/lib/coffee_script/parser.rb
CHANGED
@@ -1002,7 +1002,7 @@ racc_token_table = {
|
|
1002
1002
|
:CONTINUE => 26,
|
1003
1003
|
:FOR => 27,
|
1004
1004
|
:IN => 28,
|
1005
|
-
:
|
1005
|
+
:OF => 29,
|
1006
1006
|
:BY => 30,
|
1007
1007
|
:WHEN => 31,
|
1008
1008
|
:WHILE => 32,
|
@@ -1120,7 +1120,7 @@ Racc_token_to_s_table = [
|
|
1120
1120
|
"CONTINUE",
|
1121
1121
|
"FOR",
|
1122
1122
|
"IN",
|
1123
|
-
"
|
1123
|
+
"OF",
|
1124
1124
|
"BY",
|
1125
1125
|
"WHEN",
|
1126
1126
|
"WHILE",
|
data/lib/coffee_script/value.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coffee-script
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Ashkenas
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- examples/code.coffee
|
27
27
|
- examples/documents.coffee
|
28
28
|
- examples/poignant.coffee
|
29
|
+
- examples/potion.coffee
|
29
30
|
- examples/syntax_errors.coffee
|
30
31
|
- examples/underscore.coffee
|
31
32
|
- lib/coffee-script.rb
|