coffee-script 0.2.2 → 0.2.3
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/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
|