coffee-script 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/bin/{coffee-script → coffee} +0 -0
- data/coffee-script.gemspec +3 -3
- data/examples/code.coffee +1 -1
- data/examples/poignant.coffee +1 -1
- data/lib/coffee-script.rb +1 -1
- data/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +1 -1
- data/lib/coffee_script/command_line.rb +11 -9
- data/lib/coffee_script/grammar.y +16 -14
- data/lib/coffee_script/lexer.rb +5 -3
- data/lib/coffee_script/narwhal/coffee-script.coffee +4 -4
- data/lib/coffee_script/narwhal/js/coffee-script.js +18 -14
- data/lib/coffee_script/narwhal/js/loader.js +4 -4
- data/lib/coffee_script/nodes.rb +86 -40
- data/lib/coffee_script/parse_error.rb +2 -2
- data/lib/coffee_script/parser.output +10896 -0
- data/lib/coffee_script/parser.rb +859 -838
- data/lib/coffee_script/scope.rb +18 -3
- metadata +5 -4
data/README
CHANGED
File without changes
|
data/coffee-script.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'coffee-script'
|
3
|
-
s.version = '0.1.
|
4
|
-
s.date = '2009-12-
|
3
|
+
s.version = '0.1.5' # Keep version in sync with coffee-script.rb
|
4
|
+
s.date = '2009-12-26'
|
5
5
|
|
6
6
|
s.homepage = "http://jashkenas.github.com/coffee-script/"
|
7
7
|
s.summary = "The CoffeeScript Compiler"
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.has_rdoc = false
|
21
21
|
|
22
22
|
s.require_paths = ['lib']
|
23
|
-
s.executables = ['coffee
|
23
|
+
s.executables = ['coffee']
|
24
24
|
|
25
25
|
s.files = Dir['bin/*', 'examples/*', 'lib/**/*', 'coffee-script.gemspec', 'LICENSE', 'README']
|
26
26
|
end
|
data/examples/code.coffee
CHANGED
@@ -132,7 +132,7 @@ wednesday: => eat_breakfast(); go_to_work(); eat_dinner(); .
|
|
132
132
|
|
133
133
|
# Array slice literals.
|
134
134
|
zero_to_nine: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
135
|
-
three_to_six: zero_to_nine[3
|
135
|
+
three_to_six: zero_to_nine[3..6]
|
136
136
|
|
137
137
|
# Multiline strings with inner quotes.
|
138
138
|
story: "Lorem ipsum dolor \"sit\" amet, consectetuer adipiscing elit,
|
data/examples/poignant.coffee
CHANGED
@@ -149,5 +149,5 @@ wipe_mutterings_from: sentence =>
|
|
149
149
|
while sentence.indexOf('(') >= 0
|
150
150
|
open: sentence.indexOf('(') - 1
|
151
151
|
close: sentence.indexOf(')') + 1
|
152
|
-
sentence: sentence[0
|
152
|
+
sentence: sentence[0..open] + sentence[close..sentence.length].
|
153
153
|
sentence.
|
data/lib/coffee-script.rb
CHANGED
@@ -9,7 +9,7 @@ require "coffee_script/parse_error"
|
|
9
9
|
# Namespace for all CoffeeScript internal classes.
|
10
10
|
module CoffeeScript
|
11
11
|
|
12
|
-
VERSION = '0.1.
|
12
|
+
VERSION = '0.1.5' # Keep in sync with the gemspec.
|
13
13
|
|
14
14
|
# Compile a script (String or IO) to JavaScript.
|
15
15
|
def self.compile(script, options={})
|
@@ -5,15 +5,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../coffee-script')
|
|
5
5
|
|
6
6
|
module CoffeeScript
|
7
7
|
|
8
|
-
# The CommandLine handles all of the functionality of the `coffee
|
8
|
+
# The CommandLine handles all of the functionality of the `coffee`
|
9
9
|
# utility.
|
10
10
|
class CommandLine
|
11
11
|
|
12
12
|
BANNER = <<-EOS
|
13
|
-
coffee
|
13
|
+
coffee compiles CoffeeScript source files into JavaScript.
|
14
14
|
|
15
15
|
Usage:
|
16
|
-
coffee
|
16
|
+
coffee path/to/script.coffee
|
17
17
|
EOS
|
18
18
|
|
19
19
|
# Seconds to pause between checks for changed source files.
|
@@ -125,11 +125,13 @@ Usage:
|
|
125
125
|
end
|
126
126
|
|
127
127
|
# Compile a single source file to JavaScript.
|
128
|
-
def compile(script, source='')
|
128
|
+
def compile(script, source='error')
|
129
129
|
begin
|
130
|
-
|
131
|
-
|
132
|
-
|
130
|
+
options = {}
|
131
|
+
options[:no_wrap] = true if @options[:no_wrap]
|
132
|
+
CoffeeScript.compile(script, options)
|
133
|
+
rescue CoffeeScript::ParseError, SyntaxError => e
|
134
|
+
STDERR.puts "#{source}: #{e.message}"
|
133
135
|
exit(1) unless @options[:watch]
|
134
136
|
nil
|
135
137
|
end
|
@@ -188,8 +190,8 @@ Usage:
|
|
188
190
|
install_bundle
|
189
191
|
exit
|
190
192
|
end
|
191
|
-
opts.on_tail('--version', 'display
|
192
|
-
puts "
|
193
|
+
opts.on_tail('--version', 'display CoffeeScript version') do
|
194
|
+
puts "CoffeeScript version #{CoffeeScript::VERSION}"
|
193
195
|
exit
|
194
196
|
end
|
195
197
|
opts.on_tail('-h', '--help', 'display this help message') do
|
data/lib/coffee_script/grammar.y
CHANGED
@@ -64,11 +64,11 @@ rule
|
|
64
64
|
|
65
65
|
# The parts that are natural JavaScript expressions.
|
66
66
|
PureExpression:
|
67
|
-
|
68
|
-
| Value
|
67
|
+
Value
|
69
68
|
| Call
|
70
69
|
| Code
|
71
70
|
| Operation
|
71
|
+
| Range
|
72
72
|
;
|
73
73
|
|
74
74
|
# We have to take extra care to convert these statements into expressions.
|
@@ -120,8 +120,8 @@ rule
|
|
120
120
|
|
121
121
|
# Assignment within an object literal.
|
122
122
|
AssignObj:
|
123
|
-
IDENTIFIER ASSIGN Expression { result = AssignNode.new(val[0], val[2], :object) }
|
124
|
-
| STRING ASSIGN Expression { result = AssignNode.new(val[0], val[2], :object) }
|
123
|
+
IDENTIFIER ASSIGN Expression { result = AssignNode.new(ValueNode.new(val[0]), val[2], :object) }
|
124
|
+
| STRING ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
|
125
125
|
| Comment { result = val[0] }
|
126
126
|
;
|
127
127
|
|
@@ -144,10 +144,10 @@ rule
|
|
144
144
|
| '-' Expression = UMINUS { result = OpNode.new(val[0], val[1]) }
|
145
145
|
| NOT Expression { result = OpNode.new(val[0], val[1]) }
|
146
146
|
| '~' Expression { result = OpNode.new(val[0], val[1]) }
|
147
|
-
| '--' Expression
|
148
|
-
| '++' Expression
|
149
|
-
| Expression '--'
|
150
|
-
| Expression '++'
|
147
|
+
| '--' Expression { result = OpNode.new(val[0], val[1]) }
|
148
|
+
| '++' Expression { result = OpNode.new(val[0], val[1]) }
|
149
|
+
| Expression '--' { result = OpNode.new(val[1], val[0], nil, true) }
|
150
|
+
| Expression '++' { result = OpNode.new(val[1], val[0], nil, true) }
|
151
151
|
|
152
152
|
| Expression '*' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
153
153
|
| Expression '/' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
@@ -213,6 +213,7 @@ rule
|
|
213
213
|
# Expressions that can be treated as values.
|
214
214
|
Value:
|
215
215
|
IDENTIFIER { result = ValueNode.new(val[0]) }
|
216
|
+
| Literal { result = ValueNode.new(val[0]) }
|
216
217
|
| Array { result = ValueNode.new(val[0]) }
|
217
218
|
| Object { result = ValueNode.new(val[0]) }
|
218
219
|
| Parenthetical { result = ValueNode.new(val[0]) }
|
@@ -224,7 +225,7 @@ rule
|
|
224
225
|
Accessor:
|
225
226
|
PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
|
226
227
|
| Index { result = val[0] }
|
227
|
-
|
|
228
|
+
| Range { result = SliceNode.new(val[0]) }
|
228
229
|
;
|
229
230
|
|
230
231
|
# Indexing into an object or array.
|
@@ -232,11 +233,6 @@ rule
|
|
232
233
|
"[" Expression "]" { result = IndexNode.new(val[1]) }
|
233
234
|
;
|
234
235
|
|
235
|
-
# Array slice literal.
|
236
|
-
Slice:
|
237
|
-
"[" Expression "," Expression "]" { result = SliceNode.new(val[1], val[3]) }
|
238
|
-
;
|
239
|
-
|
240
236
|
# An object literal.
|
241
237
|
Object:
|
242
238
|
"{" AssignList "}" { result = ObjectNode.new(val[1]) }
|
@@ -273,6 +269,12 @@ rule
|
|
273
269
|
SUPER "(" ArgList ")" { result = CallNode.new(:super, val[2]) }
|
274
270
|
;
|
275
271
|
|
272
|
+
# The range literal.
|
273
|
+
Range:
|
274
|
+
"[" Value "." "." Value "]" { result = RangeNode.new(val[1], val[4]) }
|
275
|
+
| "[" Value "." "." "." Value "]" { result = RangeNode.new(val[1], val[5], true) }
|
276
|
+
;
|
277
|
+
|
276
278
|
# The array literal.
|
277
279
|
Array:
|
278
280
|
"[" ArgList "]" { result = ArrayNode.new(val[1]) }
|
data/lib/coffee_script/lexer.rb
CHANGED
@@ -19,7 +19,7 @@ module CoffeeScript
|
|
19
19
|
|
20
20
|
# Token matching regexes.
|
21
21
|
IDENTIFIER = /\A([a-zA-Z$_]\w*)/
|
22
|
-
NUMBER = /\A\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?))\b/i
|
22
|
+
NUMBER = /\A((\b|-)((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
|
23
23
|
STRING = /\A(""|''|"(.*?)[^\\]"|'(.*?)[^\\]')/m
|
24
24
|
JS = /\A(``|`(.*?)[^\\]`)/m
|
25
25
|
OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
|
@@ -75,7 +75,7 @@ module CoffeeScript
|
|
75
75
|
# Keywords are special identifiers tagged with their own name, 'if' will result
|
76
76
|
# in an [:IF, "if"] token
|
77
77
|
tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER
|
78
|
-
@tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.'
|
78
|
+
@tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2][1] == '.')
|
79
79
|
token(tag, identifier)
|
80
80
|
@i += identifier.length
|
81
81
|
end
|
@@ -130,11 +130,13 @@ module CoffeeScript
|
|
130
130
|
# We treat all other single characters as a token. Eg.: ( ) , . !
|
131
131
|
# Multi-character operators are also literal tokens, so that Racc can assign
|
132
132
|
# the proper order of operations. Multiple newlines get merged together.
|
133
|
+
# Use a trailing \ to escape newlines.
|
133
134
|
def literal_token
|
134
135
|
value = @chunk[NEWLINE, 1]
|
135
136
|
if value
|
136
137
|
@line += value.length
|
137
|
-
token("\n", "\n") unless
|
138
|
+
token("\n", "\n") unless ["\n", "\\"].include?(last_value)
|
139
|
+
@tokens.pop if last_value == "\\"
|
138
140
|
return @i += value.length
|
139
141
|
end
|
140
142
|
value = @chunk[OPERATOR, 1]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This (javascript) file is generated from lib/coffee_script/narwhal/coffee-script.coffee
|
2
2
|
|
3
|
-
# Executes the `coffee
|
3
|
+
# Executes the `coffee` Ruby program to convert from CoffeeScript
|
4
4
|
# to Javascript. Eventually this will hopefully happen entirely within JS.
|
5
5
|
|
6
6
|
# Require external dependencies.
|
@@ -9,13 +9,13 @@ File: require('file')
|
|
9
9
|
Readline: require('readline')
|
10
10
|
|
11
11
|
# The path to the CoffeeScript Compiler.
|
12
|
-
coffeePath: File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee
|
12
|
+
coffeePath: File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee')
|
13
13
|
|
14
14
|
# Our general-purpose error handler.
|
15
15
|
checkForErrors: coffeeProcess =>
|
16
16
|
return true if coffeeProcess.wait() is 0
|
17
17
|
system.stderr.print(coffeeProcess.stderr.read())
|
18
|
-
throw new Error("
|
18
|
+
throw new Error("CoffeeScript compile error").
|
19
19
|
|
20
20
|
# Run a simple REPL, round-tripping to the CoffeeScript compiler for every
|
21
21
|
# command.
|
@@ -25,7 +25,7 @@ exports.run: args =>
|
|
25
25
|
|
26
26
|
while true
|
27
27
|
try
|
28
|
-
system.stdout.write('
|
28
|
+
system.stdout.write('coffee> ').flush()
|
29
29
|
result: exports.evalCS(Readline.readline())
|
30
30
|
print(result) if result isnt undefined
|
31
31
|
catch e
|
@@ -1,31 +1,32 @@
|
|
1
1
|
(function(){
|
2
|
-
|
3
|
-
// This (javascript) file is generated from lib/coffee_script/narwhal/coffee-script.coffee Executes the `coffee
|
2
|
+
var File, OS, Readline, checkForErrors, coffeePath;
|
3
|
+
// This (javascript) file is generated from lib/coffee_script/narwhal/coffee-script.coffee Executes the `coffee` Ruby program to convert from CoffeeScript
|
4
4
|
// to Javascript. Eventually this will hopefully happen entirely within JS. Require external dependencies.
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
OS = require('os');
|
6
|
+
File = require('file');
|
7
|
+
Readline = require('readline');
|
8
8
|
// The path to the CoffeeScript Compiler.
|
9
|
-
|
9
|
+
coffeePath = File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee');
|
10
10
|
// Our general-purpose error handler.
|
11
|
-
|
11
|
+
checkForErrors = function(coffeeProcess) {
|
12
12
|
if (coffeeProcess.wait() === 0) {
|
13
13
|
return true;
|
14
14
|
}
|
15
15
|
system.stderr.print(coffeeProcess.stderr.read());
|
16
|
-
throw new Error("
|
16
|
+
throw new Error("CoffeeScript compile error");
|
17
17
|
};
|
18
18
|
// Run a simple REPL, round-tripping to the CoffeeScript compiler for every
|
19
19
|
// command.
|
20
20
|
exports.run = function(args) {
|
21
|
+
var result;
|
21
22
|
args.shift();
|
22
23
|
if (args.length) {
|
23
24
|
return require(File.absolute(args[0]));
|
24
25
|
}
|
25
26
|
while (true) {
|
26
27
|
try {
|
27
|
-
system.stdout.write('
|
28
|
-
|
28
|
+
system.stdout.write('coffee> ').flush();
|
29
|
+
result = exports.evalCS(Readline.readline());
|
29
30
|
if (result !== undefined) {
|
30
31
|
print(result);
|
31
32
|
}
|
@@ -36,13 +37,15 @@
|
|
36
37
|
};
|
37
38
|
// Compile a given CoffeeScript file into JavaScript.
|
38
39
|
exports.compileFile = function(path) {
|
39
|
-
var coffee
|
40
|
+
var coffee;
|
41
|
+
coffee = OS.popen([coffeePath, "--print", "--no-wrap", path]);
|
40
42
|
checkForErrors(coffee);
|
41
43
|
return coffee.stdout.read();
|
42
44
|
};
|
43
45
|
// Compile a string of CoffeeScript into JavaScript.
|
44
46
|
exports.compile = function(source) {
|
45
|
-
var coffee
|
47
|
+
var coffee;
|
48
|
+
coffee = OS.popen([coffeePath, "--eval", "--no-wrap"]);
|
46
49
|
coffee.stdin.write(source).flush().close();
|
47
50
|
checkForErrors(coffee);
|
48
51
|
return coffee.stdout.read();
|
@@ -53,8 +56,9 @@
|
|
53
56
|
};
|
54
57
|
// Make a factory for the CoffeeScript environment.
|
55
58
|
exports.makeNarwhalFactory = function(path) {
|
56
|
-
var code
|
57
|
-
|
59
|
+
var code, factoryText;
|
60
|
+
code = exports.compileFile(path);
|
61
|
+
factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
|
58
62
|
if (system.engine === "rhino") {
|
59
63
|
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
|
60
64
|
} else {
|
@@ -1,10 +1,10 @@
|
|
1
1
|
(function(){
|
2
|
-
|
2
|
+
var coffeescript, factories, loader;
|
3
3
|
// This (javascript) file is generated from lib/coffee_script/narwhal/loader.coffee
|
4
|
-
|
5
|
-
|
4
|
+
coffeescript = null;
|
5
|
+
factories = {
|
6
6
|
};
|
7
|
-
|
7
|
+
loader = {
|
8
8
|
// Reload the coffee-script environment from source.
|
9
9
|
reload: function(topId, path) {
|
10
10
|
coffeescript = coffeescript || require('coffee-script');
|
data/lib/coffee_script/nodes.rb
CHANGED
@@ -77,16 +77,18 @@ module CoffeeScript
|
|
77
77
|
# If this is the top-level Expressions, wrap everything in a safety closure.
|
78
78
|
def root_compile(o={})
|
79
79
|
indent = o[:no_wrap] ? '' : TAB
|
80
|
-
code = compile(o.merge(:indent => indent, :scope => Scope.new))
|
80
|
+
code = compile(o.merge(:indent => indent, :scope => Scope.new), o[:no_wrap] ? nil : :code)
|
81
81
|
code.gsub!(STRIP_TRAILING_WHITESPACE, '')
|
82
82
|
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
|
83
83
|
end
|
84
84
|
|
85
85
|
# The extra fancy is to handle pushing down returns and assignments
|
86
86
|
# recursively to the final lines of inner statements.
|
87
|
-
|
87
|
+
# Variables first defined within the Expressions body have their
|
88
|
+
# declarations pushed up to the top scope.
|
89
|
+
def compile(options={}, parent=nil)
|
88
90
|
return root_compile(options) unless options[:scope]
|
89
|
-
|
91
|
+
compiled = @expressions.map do |node|
|
90
92
|
o = super(options)
|
91
93
|
if last?(node) && (o[:return] || o[:assign])
|
92
94
|
if o[:return]
|
@@ -99,14 +101,17 @@ module CoffeeScript
|
|
99
101
|
if node.statement? || node.custom_assign?
|
100
102
|
"#{o[:indent]}#{node.compile(o)}#{node.line_ending}"
|
101
103
|
else
|
102
|
-
"#{o[:indent]}#{AssignNode.new(
|
104
|
+
"#{o[:indent]}#{AssignNode.new(o[:assign], node).compile(o)};"
|
103
105
|
end
|
104
106
|
end
|
105
107
|
else
|
106
108
|
o.delete(:return) and o.delete(:assign)
|
107
109
|
"#{o[:indent]}#{node.compile(o)}#{node.line_ending}"
|
108
110
|
end
|
109
|
-
|
111
|
+
end
|
112
|
+
scope = options[:scope]
|
113
|
+
declarations = scope.any_declared? && parent == :code ? "#{options[:indent]}var #{scope.declared_variables.join(', ')};\n" : ''
|
114
|
+
code = declarations + compiled.join("\n")
|
110
115
|
write(code)
|
111
116
|
end
|
112
117
|
end
|
@@ -202,7 +207,7 @@ module CoffeeScript
|
|
202
207
|
|
203
208
|
def compile(o={})
|
204
209
|
o = super(o)
|
205
|
-
args = @arguments.map{|a| a.compile(o
|
210
|
+
args = @arguments.map{|a| a.compile(o) }.join(', ')
|
206
211
|
return write(compile_super(args, o)) if super?
|
207
212
|
prefix = @new ? "new " : ''
|
208
213
|
write("#{prefix}#{@variable.compile(o)}(#{args})")
|
@@ -300,28 +305,60 @@ module CoffeeScript
|
|
300
305
|
end
|
301
306
|
end
|
302
307
|
|
308
|
+
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
309
|
+
# or to specify a range for array comprehensions.
|
310
|
+
class RangeNode
|
311
|
+
attr_reader :from, :to
|
312
|
+
|
313
|
+
def initialize(from, to, exclusive=false)
|
314
|
+
@from, @to, @exclusive = from, to, exclusive
|
315
|
+
end
|
316
|
+
|
317
|
+
def exclusive?
|
318
|
+
@exclusive
|
319
|
+
end
|
320
|
+
|
321
|
+
def less_operator
|
322
|
+
@exclusive ? '<' : '<='
|
323
|
+
end
|
324
|
+
|
325
|
+
def greater_operator
|
326
|
+
@exclusive ? '>' : '>='
|
327
|
+
end
|
328
|
+
|
329
|
+
def compile(o, fv, tv)
|
330
|
+
fvv, tvv = @from.compile(o), @to.compile(o)
|
331
|
+
vars = "#{fv}=#{fvv}, #{tv}=#{tvv}"
|
332
|
+
compare = "(#{fvv} <= #{tvv} ? #{fv} #{less_operator} #{tv} : #{fv} #{greater_operator} #{tv})"
|
333
|
+
incr = "(#{fvv} <= #{tvv} ? #{fv} += 1 : #{fv} -= 1)"
|
334
|
+
"#{vars}; #{compare}; #{incr}"
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
|
303
339
|
# An array slice literal. Unlike JavaScript's Array#slice, the second parameter
|
304
340
|
# specifies the index of the end of the slice (just like the first parameter)
|
305
341
|
# is the index of the beginning.
|
306
342
|
class SliceNode < Node
|
307
|
-
attr_reader :
|
343
|
+
attr_reader :range
|
308
344
|
|
309
|
-
def initialize(
|
310
|
-
@
|
345
|
+
def initialize(range)
|
346
|
+
@range = range
|
311
347
|
end
|
312
348
|
|
313
349
|
def compile(o={})
|
314
|
-
o
|
315
|
-
|
350
|
+
o = super(o)
|
351
|
+
from = @range.from.compile(o)
|
352
|
+
to = @range.to.compile(o)
|
353
|
+
plus_part = @range.exclusive? ? '' : ' + 1'
|
354
|
+
write(".slice(#{from}, #{to}#{plus_part})")
|
316
355
|
end
|
317
356
|
end
|
318
357
|
|
319
358
|
# Setting the value of a local variable, or the value of an object property.
|
320
359
|
class AssignNode < Node
|
321
|
-
LEADING_VAR = /\Avar\s+/
|
322
360
|
PROTO_ASSIGN = /\A(\S+)\.prototype/
|
323
361
|
|
324
|
-
statement
|
325
362
|
custom_return
|
326
363
|
|
327
364
|
attr_reader :variable, :value, :context
|
@@ -336,19 +373,16 @@ module CoffeeScript
|
|
336
373
|
|
337
374
|
def compile(o={})
|
338
375
|
o = super(o)
|
339
|
-
name = @variable.
|
340
|
-
last = @variable.
|
376
|
+
name = @variable.compile(o)
|
377
|
+
last = @variable.last.to_s
|
341
378
|
proto = name[PROTO_ASSIGN, 1]
|
342
|
-
o = o.merge(:assign =>
|
379
|
+
o = o.merge(:assign => @variable, :last_assign => last, :proto_assign => proto)
|
343
380
|
postfix = o[:return] ? ";\n#{o[:indent]}return #{name}" : ''
|
344
|
-
return write("#{
|
381
|
+
return write("#{name}: #{@value.compile(o)}") if @context == :object
|
345
382
|
return write("#{name} = #{@value.compile(o)}#{postfix}") if @variable.properties? && !@value.custom_assign?
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
def_part = defined || o[:no_wrap] ? name : "var #{name}"
|
350
|
-
val_part = @value.compile(o).sub(LEADING_VAR, '')
|
351
|
-
write("#{def_part} = #{val_part}#{postfix}")
|
383
|
+
o[:scope].find(name) unless @variable.properties?
|
384
|
+
return write(@value.compile(o)) if @value.custom_assign?
|
385
|
+
write("#{name} = #{@value.compile(o)}#{postfix}")
|
352
386
|
end
|
353
387
|
end
|
354
388
|
|
@@ -416,8 +450,8 @@ module CoffeeScript
|
|
416
450
|
o[:indent] += TAB
|
417
451
|
o.delete(:assign)
|
418
452
|
o.delete(:no_wrap)
|
419
|
-
@params.each {|id| o[:scope].
|
420
|
-
code = @body.compile(o)
|
453
|
+
@params.each {|id| o[:scope].parameter(id.to_s) }
|
454
|
+
code = @body.compile(o, :code)
|
421
455
|
write("function(#{@params.join(', ')}) {\n#{code}\n#{indent}}")
|
422
456
|
end
|
423
457
|
end
|
@@ -480,7 +514,7 @@ module CoffeeScript
|
|
480
514
|
o = super(o)
|
481
515
|
o.delete(:return)
|
482
516
|
indent = o[:indent] + TAB
|
483
|
-
cond = @condition.compile(o
|
517
|
+
cond = @condition.compile(o)
|
484
518
|
write("while (#{cond}) {\n#{@body.compile(o.merge(:indent => indent))}\n#{o[:indent]}}")
|
485
519
|
end
|
486
520
|
end
|
@@ -506,27 +540,36 @@ module CoffeeScript
|
|
506
540
|
|
507
541
|
def compile(o={})
|
508
542
|
o = super(o)
|
543
|
+
range = @source.is_a?(RangeNode)
|
509
544
|
scope = o[:scope]
|
510
545
|
name_found = scope.find(@name)
|
511
546
|
index_found = @index && scope.find(@index)
|
512
547
|
svar = scope.free_variable
|
513
|
-
ivar = scope.free_variable
|
548
|
+
ivar = range ? name : scope.free_variable
|
514
549
|
lvar = scope.free_variable
|
515
550
|
rvar = scope.free_variable
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
551
|
+
index_name = @index ? @index : nil
|
552
|
+
if range
|
553
|
+
source_part = ''
|
554
|
+
var_part = ''
|
555
|
+
index_part = ''
|
556
|
+
index_var = scope.free_variable
|
557
|
+
for_part = "#{index_var}=0, #{@source.compile(o, ivar, lvar)}, #{index_var}++"
|
558
|
+
else
|
559
|
+
index_var = nil
|
560
|
+
source_part = "#{svar} = #{@source.compile(o)};\n#{o[:indent]}"
|
561
|
+
for_part = "#{ivar}=0, #{lvar}=#{svar}.length; #{ivar}<#{lvar}; #{ivar}++"
|
562
|
+
var_part = "\n#{o[:indent] + TAB}#{@name} = #{svar}[#{ivar}];"
|
563
|
+
index_part = @index ? "\n#{o[:indent] + TAB}#{index_name} = #{ivar};" : ''
|
564
|
+
end
|
522
565
|
body = @body
|
523
566
|
suffix = ';'
|
524
|
-
set_result = "
|
525
|
-
save_result = "#{rvar}[#{ivar}] = "
|
567
|
+
set_result = "#{rvar} = [];\n#{o[:indent]}"
|
568
|
+
save_result = "#{rvar}[#{index_var || ivar}] = "
|
526
569
|
return_result = rvar
|
527
570
|
|
528
571
|
if o[:return] || o[:assign]
|
529
|
-
return_result = "#{o[:assign]} = #{return_result}" if o[:assign]
|
572
|
+
return_result = "#{o[:assign].compile(o)} = #{return_result}" if o[:assign]
|
530
573
|
return_result = "return #{return_result}" if o[:return]
|
531
574
|
if @filter
|
532
575
|
body = CallNode.new(ValueNode.new(LiteralNode.new(rvar), [AccessorNode.new('push')]), [@body])
|
@@ -541,7 +584,7 @@ module CoffeeScript
|
|
541
584
|
return_result = "\n#{o[:indent]}#{return_result};"
|
542
585
|
indent = o[:indent] + TAB
|
543
586
|
body = body.compile(o.merge(:indent => indent))
|
544
|
-
write("#{source_part}
|
587
|
+
write("#{source_part}#{set_result}for (#{for_part}) {#{var_part}#{index_part}\n#{indent}#{save_result}#{body}#{suffix}\n#{o[:indent]}}#{return_result}")
|
545
588
|
end
|
546
589
|
end
|
547
590
|
|
@@ -588,7 +631,9 @@ module CoffeeScript
|
|
588
631
|
end
|
589
632
|
end
|
590
633
|
|
591
|
-
# An extra set of
|
634
|
+
# An extra set of parentheses, supplied by the script source.
|
635
|
+
# You can't wrap parentheses around bits that get compiled into JS statements,
|
636
|
+
# unfortunately.
|
592
637
|
class ParentheticalNode < Node
|
593
638
|
attr_reader :expressions
|
594
639
|
|
@@ -597,7 +642,7 @@ module CoffeeScript
|
|
597
642
|
end
|
598
643
|
|
599
644
|
def statement?
|
600
|
-
@expressions.statement?
|
645
|
+
@expressions.unwrap.statement?
|
601
646
|
end
|
602
647
|
|
603
648
|
def custom_assign?
|
@@ -609,10 +654,11 @@ module CoffeeScript
|
|
609
654
|
end
|
610
655
|
|
611
656
|
def compile(o={})
|
657
|
+
raise SyntaxError, "parentheses can't be wrapped around a statement" if statement?
|
612
658
|
o = super(o)
|
613
659
|
compiled = @expressions.compile(o)
|
614
660
|
compiled = compiled[0...-1] if compiled[-1..-1] == ';'
|
615
|
-
write(
|
661
|
+
write("(#{compiled})")
|
616
662
|
end
|
617
663
|
end
|
618
664
|
|