coffee-script 0.1.4 → 0.1.5
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 +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
|
|