Compare commits

...

24 Commits
0.1.2 ... 0.1.4

Author SHA1 Message Date
Jeremy Ashkenas
88fe4f6fd1 CoffeeScript 0.1.4 2009-12-25 14:43:24 -08:00
Jeremy Ashkenas
03a90928e1 moved the coffeescript extension over from .cs to .coffee -- let's leave C# in peace. Changed array comprehensions to always return their mapped result, even when unassigned 2009-12-25 14:18:05 -08:00
Jeremy Ashkenas
67865d3341 stopped using __proto__, instead, using a variant of goog.inherits for extends and super() 2009-12-25 13:57:47 -08:00
Jeremy Ashkenas
0337513172 ForBody is really the ForSource 2009-12-25 13:40:57 -08:00
Jeremy Ashkenas
1ee2c53391 cleaned up the for grammar and eliminated a shift/reduce conflict 2009-12-25 13:39:33 -08:00
Jeremy Ashkenas
4b7c965101 make equals signs full equals of colons -- you can use them inside of object literals now too 2009-12-25 13:21:17 -08:00
Jeremy Ashkenas
11c394fb7e allowing = to assign 2009-12-25 07:42:27 -08:00
Jeremy Ashkenas
54a7c405e7 going back to familiar operators +: is just too strange 2009-12-25 07:31:51 -08:00
Jeremy Ashkenas
781f3b5fa4 added a test to make sure that chained calls work 2009-12-25 07:16:59 -08:00
Jeremy Ashkenas
2393472924 allowing chained function calls, one right after another 2009-12-25 07:08:57 -08:00
Jeremy Ashkenas
859ab7583f bumping to 0.1.3 ... here we go 2009-12-25 00:16:56 -08:00
Jeremy Ashkenas
3eedd5bb50 better error warnings on the command line 2009-12-25 00:02:27 -08:00
Jeremy Ashkenas
5b7e695f6c removed bin/cs in favor of a more comprehensive coffee-script command ... now with --interactive and --run 2009-12-24 23:57:27 -08:00
Jeremy Ashkenas
1e3182727b majorly cleaned up the CoffeeScript that defines the Narwhal integration 2009-12-24 23:28:01 -08:00
Jeremy Ashkenas
e595dbfcee the narwhal integration written in JavaScript has been replaced with CoffeeScript, and compiler-generated variable names now start with '__' 2009-12-24 23:09:24 -08:00
Jeremy Ashkenas
12b830893d sped up the execution test a good deal by running it all in one pass 2009-12-24 22:29:30 -08:00
Jeremy Ashkenas
cca80342aa making all assignment-y operators use a colon -- now it's +: -: *: /:, and friends 2009-12-24 22:25:29 -08:00
Jeremy Ashkenas
4412f590cf removed dependency on v8 in favor of bin/cs 2009-12-24 22:08:32 -08:00
tlrobinson
0cd2d78027 Print compiler errors to stderr 2009-12-24 19:34:17 -08:00
Jeremy Ashkenas
be672ebfc1 fixed the bin/cs repl to save assignment between commands by using the new --no-wrap 2009-12-24 17:45:23 -08:00
Jeremy Ashkenas
9047c87567 the --no-wrap option now disables top-level var declarations 2009-12-24 17:37:24 -08:00
Jeremy Ashkenas
31d630bb91 updating docs for isnt 2009-12-24 17:22:46 -08:00
Jeremy Ashkenas
7a2f5a333f trading aint for isnt -- let's be serious 2009-12-24 17:21:20 -08:00
Jeremy Ashkenas
66303636dc allowing quoted strings within object assignment, a in JS and JSON 2009-12-24 17:14:53 -08:00
73 changed files with 1705 additions and 1561 deletions

2
README
View File

@@ -26,7 +26,7 @@
gem install coffee-script
Compile a script:
coffee-script /path/to/script.cs
coffee-script /path/to/script.coffee
For documentation, usage, and examples, see:
http://jashkenas.github.com/coffee-script/

View File

@@ -10,15 +10,24 @@ task :test do
Dir['test/*/**/test_*.rb'].each {|test| require test }
end
desc "Recompile the Racc parser (pass -v and -g for verbose debugging)"
task :build, :extra_args do |t, args|
sh "racc #{args[:extra_args]} -o lib/coffee_script/parser.rb lib/coffee_script/grammar.y"
namespace :build do
desc "Recompile the Racc parser (pass -v and -g for verbose debugging)"
task :parser, :racc_args do |t, args|
sh "racc #{args[:racc_args]} -o lib/coffee_script/parser.rb lib/coffee_script/grammar.y"
end
desc "Compile the Narwhal interface for --interactive and --run"
task :narwhal do
sh "bin/coffee-script lib/coffee_script/narwhal/*.coffee -o lib/coffee_script/narwhal/js"
end
end
desc "Build the documentation page"
task :doc do
source = 'documentation/index.html.erb'
child = fork { exec "bin/coffee-script documentation/cs/*.cs -o documentation/js -w" }
child = fork { exec "bin/coffee-script documentation/coffee/*.coffee -o documentation/js -w" }
at_exit { Process.kill("INT", child) }
Signal.trap("INT") { exit }
loop do

3
bin/cs
View File

@@ -1,3 +0,0 @@
#!/usr/bin/env narwhal
require("coffee-script").run(system.args);

View File

@@ -1,7 +1,7 @@
Gem::Specification.new do |s|
s.name = 'coffee-script'
s.version = '0.1.2' # Keep version in sync with coffee-script.rb
s.date = '2009-12-24'
s.version = '0.1.4' # Keep version in sync with coffee-script.rb
s.date = '2009-12-25'
s.homepage = "http://jashkenas.github.com/coffee-script/"
s.summary = "The CoffeeScript Compiler"

View File

@@ -1,6 +1,6 @@
launch() if ignition is on
volume: 10 if band aint spinal_tap
volume: 10 if band isnt spinal_tap
let_the_wild_rumpus_begin() unless answer is no

View File

@@ -6,4 +6,4 @@ if happy and knows_it
date: if friday then sue else jill.
expensive ||: do_the_math()
expensive ||= do_the_math()

View File

@@ -3,13 +3,13 @@ Animal.prototype.move: meters =>
alert(this.name + " moved " + meters + "m.").
Snake: name => this.name: name.
Snake extends new Animal()
Snake extends Animal
Snake.prototype.move: =>
alert("Slithering...")
super(5).
Horse: name => this.name: name.
Horse extends new Animal()
Horse extends Animal
Horse.prototype.move: =>
alert("Galloping...")
super(45).

View File

@@ -1,3 +0,0 @@
# CoffeeScript on the left, JS on the right.
square: x => x * x.

View File

@@ -1,11 +0,0 @@
# Comments start with hash marks.
# Periods mark the end of a block.
left_hand: if raining then umbrella else parasol.
# To signal the beginning of the next expression,
# use "then", or a newline.
left_hand: if raining
umbrella
else
parasol.

View File

@@ -3,7 +3,7 @@
def code_for(file, executable=false)
@stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/
return '' unless File.exists?("documentation/js/#{file}.js")
cs = File.read("documentation/cs/#{file}.cs")
cs = File.read("documentation/coffee/#{file}.coffee")
js = File.read("documentation/js/#{file}.js").gsub(@stripper, '')
cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false)
jshtml = Uv.parse(js, 'xhtml', 'javascript', false, 'idle', false)
@@ -37,8 +37,6 @@
equivalent in JavaScript, it's just another way of saying it.
</p>
<!-- <%# code_for('intro') %>-->
<p>
<b>Disclaimer:</b>
CoffeeScript is just for fun and seriously alpha. I'm sure that there are still
@@ -83,7 +81,7 @@
<%= code_for('overview', 'cubed_list') %>
<h2 id="installation">Installation and Usage</h2>
<p>
The CoffeeScript compiler is written in pure Ruby, and is available
as a Ruby Gem.
@@ -94,15 +92,32 @@ gem install coffee-script</pre>
<p>
Installing the gem provides the <tt>coffee-script</tt> command, which can
be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug them. By default, <tt>coffee-script</tt> writes out the
JavaScript as <tt>.js</tt> files in the same directory, but output
be used to compile CoffeeScript <tt>.coffee</tt> files into JavaScript, as
well as debug them. In conjunction with
<a href="http://narwhaljs.org/">Narwhal</a>, the <tt>coffee-script</tt>
command also provides direct evaluation and an interactive REPL.
When compiling to JavaScript, <tt>coffee-script</tt> writes the output
as <tt>.js</tt> files in the same directory by default, but output
can be customized with the following options:
</p>
<table>
<tr>
<td width="25%"><code>-o, --output [DIR]</code></td>
<td width="25%"><code>-i, --interactive</code></td>
<td>
Launch an interactive CoffeeScript session.
Requires <a href="http://narwhaljs.org/">Narwhal</a>.
</td>
</tr>
<tr>
<td><code>-r, --run</code></td>
<td>
Compile and execute the CoffeeScripts without saving the intermediate
JavaScript. Requires <a href="http://narwhaljs.org/">Narwhal</a>.
</td>
</tr>
<tr>
<td><code>-o, --output [DIR]</code></td>
<td>
Write out all compiled JavaScript files into the specified directory.
</td>
@@ -125,7 +140,7 @@ gem install coffee-script</pre>
<td><code>-l, --lint</code></td>
<td>
If the <tt>jsl</tt> (JavaScript Lint) command is installed, use it
to check the compilation of a CoffeeScript file. (Handy in
to check the compilation of a CoffeeScript file. (Handy in
conjunction with <tt>--watch</tt>)
</td>
</tr>
@@ -151,6 +166,14 @@ gem install coffee-script</pre>
AST.
</td>
</tr>
<tr>
<td><code>-n, --no-wrap</code></td>
<td>
Compile the JavaScript without the top-level function safety wrapper
or var declarations, for situations where you want to add every
variable to global scope.
</td>
</tr>
<tr>
<td><code>--install-bundle</code></td>
<td>
@@ -164,9 +187,10 @@ gem install coffee-script</pre>
</p>
<pre>
coffee-script path/to/script.cs
coffee-script --watch --lint experimental.cs
coffee-script --print app/scripts/*.cs > concatenation.js</pre>
coffee-script path/to/script.coffee
coffee-script --interactive
coffee-script --watch --lint experimental.coffee
coffee-script --print app/scripts/*.coffee > concatenation.js</pre>
<h2>Language Reference</h2>
@@ -186,15 +210,15 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
the line will do just as well. All other whitespace is
not significant. Instead of using curly braces <tt>{ }</tt>
to delimit a block of code, use a period <tt>.</tt> to mark the end of a
block, for
<a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
block, for
<a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>.
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Functions are defined by a list of parameters, an arrow, and the
Functions are defined by a list of parameters, an arrow, and the
function body. The empty function looks like this: <tt>=>.</tt>
</p>
<%= code_for('functions', 'cube(5)') %>
@@ -250,9 +274,9 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
</p>
<%= code_for('conditionals') %>
<p>
The conditional assignment operators are available: <tt>||:</tt>,
The conditional assignment operators are available: <tt>||=</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;:</tt>, which only replaces the value of
is falsy, and <tt>&amp;&amp;=</tt>, which only replaces the value of
truthy variables.
</p>
@@ -270,7 +294,7 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
The same mechanism is used to push down assignment through <b>switch</b>
statements, and <b>if-elses</b> (although the ternary operator is preferred).
</p>
<p id="aliases">
<b class="header">Aliases</b>
Because the <tt>==</tt> operator frequently causes undesirable coercion,
@@ -278,7 +302,7 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
CoffeeScript compiles <tt>==</tt> into <tt>===</tt>, and <tt>!=</tt> into
<tt>!==</tt>.
In addition, <tt>is</tt> compiles into <tt>===</tt>,
and <tt>aint</tt> into <tt>!==</tt>.
and <tt>isnt</tt> into <tt>!==</tt>.
</p>
<p>
You can use <tt>not</tt> as an alias for <tt>!</tt>.
@@ -289,7 +313,7 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
</p>
<p>
Instead of a newline or semicolon, <tt>then</tt> can be used to separate
conditions from expressions, in <b>while</b>,
conditions from expressions, in <b>while</b>,
<b>if</b>/<b>else</b>, and <b>switch</b>/<b>when</b> statements.
</p>
<p>
@@ -382,14 +406,14 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
Multiline strings are allowed in CoffeeScript.
</p>
<%= code_for('strings', 'moby_dick') %>
<h2 id="contributing">Contributing</h2>
<p>
Here's a wish list of things that would be wonderful to have in
CoffeeScript:
</p>
<ul>
<li>
A JavaScript version of the compiler, perhaps using Alessandro Warth's
@@ -404,7 +428,7 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
should be able to compile properly.
</li>
<li>
A tutorial that introduces CoffeeScript from the ground up for folks
A tutorial that introduces CoffeeScript from the ground up for folks
without knowledge of JavaScript.
</li>
<li>
@@ -412,31 +436,57 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
having a JavaScript version of the compiler).
</li>
<li>
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
string manipulation. Techniques for cleaning this up across the board
would be appreciated.
</li>
</ul>
<h2 id="change_log">Change Log</h2>
<p>
<b class="header" style="margin-top: 20px;">0.1.4</b>
The official CoffeeScript extension is now <tt>.coffee</tt> instead of
<tt>.cs</tt>, which properly belongs to
<a href="http://en.wikipedia.org/wiki/C_Sharp_(programming_language)">C#</a>.
Due to popular demand, you can now also use <tt>=</tt> to assign. Unlike
JavaScript, <tt>=</tt> can also be used within object literals, interchangeably
with <tt>:</tt>. Made a grammatical fix for chained function calls
like <tt>func(1)(2)(3)(4)</tt>. Inheritance and super no longer use
<tt>__proto__</tt>, so they should be IE-compatible now.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.3</b>
The <tt>coffee-script</tt> command now includes <tt>--interactive</tt>,
which launches an interactive CoffeeScript session, and <tt>--run</tt>,
which directly compiles and executes a script. Both options depend on a
working installation of Narwhal.
The <tt>aint</tt> keyword has been replaced by <tt>isnt</tt>, which goes
together a little smoother with <tt>is</tt>.
Quoted strings are now allowed as identifiers within object literals: eg.
<tt>{"5+5": 10}</tt>.
All assignment operators now use a colon: <tt>+:</tt>, <tt>-:</tt>,
<tt>*:</tt>, etc.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.2</b>
Fixed a bug with calling <tt>super()</tt> through more than one level of
Fixed a bug with calling <tt>super()</tt> through more than one level of
inheritance, with the re-addition of the <tt>extends</tt> keyword.
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
support (as a Tusk package), contributed by
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
support (as a Tusk package), contributed by
<a href="http://tlrobinson.net/">Tom Robinson</a>, including
<b>bin/cs</b> as a CoffeeScript REPL and interpreter.
New <tt>--no-wrap</tt> option to suppress the safety function
wrapper.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.1</b>
Added <tt>instanceof</tt> and <tt>typeof</tt> as operators.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.0</b>
Initial CoffeeScript release.

View File

@@ -2,18 +2,20 @@
// Eat lunch.
var lunch;
var a = ['toast', 'cheese', 'wine'];
var d = [];
for (var b=0, c=a.length; b<c; b++) {
var food = a[b];
d[b] = food.eat();
var __a = ['toast', 'cheese', 'wine'];
var __d = [];
for (var __b=0, __c=__a.length; __b<__c; __b++) {
var food = __a[__b];
__d[__b] = food.eat();
}
lunch = d;
lunch = __d;
// Zebra-stripe a table.
var e = table;
for (var f=0, g=e.length; f<g; f++) {
var row = e[f];
var i = f;
i % 2 === 0 ? highlight(row) : null;
var __e = table;
var __h = [];
for (var __f=0, __g=__e.length; __f<__g; __f++) {
var row = __e[__f];
var i = __f;
__h[__f] = i % 2 === 0 ? highlight(row) : null;
}
__h;
})();

View File

@@ -23,11 +23,11 @@
};
// Array comprehensions:
var cubed_list;
var a = list;
var d = [];
for (var b=0, c=a.length; b<c; b++) {
var num = a[b];
d[b] = math.cube(num);
var __a = list;
var __d = [];
for (var __b=0, __c=__a.length; __b<__c; __b++) {
var num = __a[__b];
__d[__b] = math.cube(num);
}
cubed_list = d;
cubed_list = __d;
})();

View File

@@ -8,19 +8,23 @@
this.name = name;
return this.name;
};
Snake.prototype.__proto__ = new Animal();
Snake.__superClass__ = Animal.prototype;
Snake.prototype = new Animal();
Snake.prototype.constructor = Snake;
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.prototype.__proto__.move.call(this, 5);
return Snake.__superClass__.move.call(this, 5);
};
var Horse = function(name) {
this.name = name;
return this.name;
};
Horse.prototype.__proto__ = new Animal();
Horse.__superClass__ = Animal.prototype;
Horse.prototype = new Animal();
Horse.prototype.constructor = Horse;
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.prototype.__proto__.move.call(this, 45);
return Horse.__superClass__.move.call(this, 45);
};
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");

View File

@@ -5,7 +5,7 @@ sum: x, y => x + y.
odd: x => x % 2 is 0.
even: x => x % 2 aint 0.
even: x => x % 2 isnt 0.
run_loop: =>
fire_events( e => e.stopPropagation(). )
@@ -62,8 +62,8 @@ race: =>
race().
# Conditional assignment:
good ||: evil
wine &&: cheese
good ||= evil
wine &&= cheese
# Nested property access and calls.
((moon.turn(360))).shapes[3].move({x: 45, y: 30}).position['top'].offset('x')
@@ -145,13 +145,13 @@ Animal.prototype.move: meters =>
alert(this.name + " moved " + meters + "m.").
Snake: name => this.name: name.
Snake extends new Animal()
Snake extends Animal
Snake.prototype.move: =>
alert('Slithering...')
super(5).
Horse: name => this.name: name.
Horse extends new Animal()
Horse extends Animal
Horse.prototype.move: =>
alert('Galloping...')
super(45).

View File

@@ -49,7 +49,7 @@ _.each: obj, iterator, context =>
return iterator.call(context, item, i, obj) for item, i in obj. if _.isArray(obj) or _.isArguments(obj)
iterator.call(context, obj[key], key, obj) for key in _.keys(obj).
catch e
throw e if e aint breaker.
throw e if e isnt breaker.
obj.
# Return the results of applying the iterator to each element. Use JavaScript

View File

@@ -23,8 +23,6 @@
equivalent in JavaScript, it's just another way of saying it.
</p>
<!-- -->
<p>
<b>Disclaimer:</b>
CoffeeScript is just for fun and seriously alpha. I'm sure that there are still
@@ -112,13 +110,13 @@ cubed_list<span class="Keyword">:</span> math.cube(num) <span class="Keyword">fo
};
<span class="Comment"><span class="Comment">//</span> Array comprehensions:</span>
<span class="Storage">var</span> cubed_list;
<span class="Storage">var</span> a <span class="Keyword">=</span> list;
<span class="Storage">var</span> d <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (<span class="Storage">var</span> b<span class="Keyword">=</span><span class="Number">0</span>, c<span class="Keyword">=</span>a.<span class="LibraryConstant">length</span>; b<span class="Keyword">&lt;</span>c; b<span class="Keyword">++</span>) {
<span class="Storage">var</span> num <span class="Keyword">=</span> a[b];
d[b] <span class="Keyword">=</span> math.cube(num);
<span class="Storage">var</span> __a <span class="Keyword">=</span> list;
<span class="Storage">var</span> __d <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (<span class="Storage">var</span> __b<span class="Keyword">=</span><span class="Number">0</span>, __c<span class="Keyword">=</span>__a.<span class="LibraryConstant">length</span>; __b<span class="Keyword">&lt;</span>__c; __b<span class="Keyword">++</span>) {
<span class="Storage">var</span> num <span class="Keyword">=</span> __a[__b];
__d[__b] <span class="Keyword">=</span> math.cube(num);
}
cubed_list <span class="Keyword">=</span> d;
cubed_list <span class="Keyword">=</span> __d;
</pre><button onclick='javascript:
// Assignment:
var number = 42;
@@ -143,17 +141,17 @@ var math = {
};
// Array comprehensions:
var cubed_list;
var a = list;
var d = [];
for (var b=0, c=a.length; b<c; b++) {
var num = a[b];
d[b] = math.cube(num);
var __a = list;
var __d = [];
for (var __b=0, __c=__a.length; __b<__c; __b++) {
var num = __a[__b];
__d[__b] = math.cube(num);
}
cubed_list = d;
cubed_list = __d;
;alert(cubed_list);'>run: cubed_list</button><br class='clear' /></div>
<h2 id="installation">Installation and Usage</h2>
<p>
The CoffeeScript compiler is written in pure Ruby, and is available
as a Ruby Gem.
@@ -164,15 +162,32 @@ gem install coffee-script</pre>
<p>
Installing the gem provides the <tt>coffee-script</tt> command, which can
be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug them. By default, <tt>coffee-script</tt> writes out the
JavaScript as <tt>.js</tt> files in the same directory, but output
be used to compile CoffeeScript <tt>.coffee</tt> files into JavaScript, as
well as debug them. In conjunction with
<a href="http://narwhaljs.org/">Narwhal</a>, the <tt>coffee-script</tt>
command also provides direct evaluation and an interactive REPL.
When compiling to JavaScript, <tt>coffee-script</tt> writes the output
as <tt>.js</tt> files in the same directory by default, but output
can be customized with the following options:
</p>
<table>
<tr>
<td width="25%"><code>-o, --output [DIR]</code></td>
<td width="25%"><code>-i, --interactive</code></td>
<td>
Launch an interactive CoffeeScript session.
Requires <a href="http://narwhaljs.org/">Narwhal</a>.
</td>
</tr>
<tr>
<td><code>-r, --run</code></td>
<td>
Compile and execute the CoffeeScripts without saving the intermediate
JavaScript. Requires <a href="http://narwhaljs.org/">Narwhal</a>.
</td>
</tr>
<tr>
<td><code>-o, --output [DIR]</code></td>
<td>
Write out all compiled JavaScript files into the specified directory.
</td>
@@ -195,7 +210,7 @@ gem install coffee-script</pre>
<td><code>-l, --lint</code></td>
<td>
If the <tt>jsl</tt> (JavaScript Lint) command is installed, use it
to check the compilation of a CoffeeScript file. (Handy in
to check the compilation of a CoffeeScript file. (Handy in
conjunction with <tt>--watch</tt>)
</td>
</tr>
@@ -221,6 +236,14 @@ gem install coffee-script</pre>
AST.
</td>
</tr>
<tr>
<td><code>-n, --no-wrap</code></td>
<td>
Compile the JavaScript without the top-level function safety wrapper
or var declarations, for situations where you want to add every
variable to global scope.
</td>
</tr>
<tr>
<td><code>--install-bundle</code></td>
<td>
@@ -234,9 +257,10 @@ gem install coffee-script</pre>
</p>
<pre>
coffee-script path/to/script.cs
coffee-script --watch --lint experimental.cs
coffee-script --print app/scripts/*.cs > concatenation.js</pre>
coffee-script path/to/script.coffee
coffee-script --interactive
coffee-script --watch --lint experimental.coffee
coffee-script --print app/scripts/*.coffee > concatenation.js</pre>
<h2>Language Reference</h2>
@@ -256,15 +280,15 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
the line will do just as well. All other whitespace is
not significant. Instead of using curly braces <tt>{ }</tt>
to delimit a block of code, use a period <tt>.</tt> to mark the end of a
block, for
<a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
block, for
<a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>.
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Functions are defined by a list of parameters, an arrow, and the
Functions are defined by a list of parameters, an arrow, and the
function body. The empty function looks like this: <tt>=>.</tt>
</p>
<div class='code'><pre class="idle"><span class="FunctionName">square</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> x <span class="Keyword">*</span> x.
@@ -383,7 +407,7 @@ var new_num = change_numbers();
date<span class="Keyword">:</span> <span class="Keyword">if</span> friday <span class="Keyword">then</span> sue <span class="Keyword">else</span> jill.
expensive <span class="Keyword">||</span><span class="Keyword">:</span> do_the_math()
expensive <span class="Keyword">||</span><span class="Keyword">=</span> do_the_math()
</pre><pre class="idle"><span class="Storage">var</span> mood;
<span class="Keyword">if</span> (singing) {
mood <span class="Keyword">=</span> greatly_improved;
@@ -396,9 +420,9 @@ expensive <span class="Keyword">||</span><span class="Keyword">:</span> do_the_m
expensive <span class="Keyword">=</span> expensive <span class="Keyword">||</span> do_the_math();
</pre><br class='clear' /></div>
<p>
The conditional assignment operators are available: <tt>||:</tt>,
The conditional assignment operators are available: <tt>||=</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;:</tt>, which only replaces the value of
is falsy, and <tt>&amp;&amp;=</tt>, which only replaces the value of
truthy variables.
</p>
@@ -445,7 +469,7 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
The same mechanism is used to push down assignment through <b>switch</b>
statements, and <b>if-elses</b> (although the ternary operator is preferred).
</p>
<p id="aliases">
<b class="header">Aliases</b>
Because the <tt>==</tt> operator frequently causes undesirable coercion,
@@ -453,7 +477,7 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
CoffeeScript compiles <tt>==</tt> into <tt>===</tt>, and <tt>!=</tt> into
<tt>!==</tt>.
In addition, <tt>is</tt> compiles into <tt>===</tt>,
and <tt>aint</tt> into <tt>!==</tt>.
and <tt>isnt</tt> into <tt>!==</tt>.
</p>
<p>
You can use <tt>not</tt> as an alias for <tt>!</tt>.
@@ -464,7 +488,7 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
</p>
<p>
Instead of a newline or semicolon, <tt>then</tt> can be used to separate
conditions from expressions, in <b>while</b>,
conditions from expressions, in <b>while</b>,
<b>if</b>/<b>else</b>, and <b>switch</b>/<b>when</b> statements.
</p>
<p>
@@ -476,7 +500,7 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
</p>
<div class='code'><pre class="idle">launch() <span class="Keyword">if</span> ignition <span class="Keyword">is</span> <span class="BuiltInConstant">on</span>
volume<span class="Keyword">:</span> <span class="Number">10</span> <span class="Keyword">if</span> band <span class="Keyword">aint</span> spinal_tap
volume<span class="Keyword">:</span> <span class="Number">10</span> <span class="Keyword">if</span> band <span class="Keyword">isnt</span> spinal_tap
let_the_wild_rumpus_begin() <span class="Keyword">unless</span> answer <span class="Keyword">is</span> <span class="BuiltInConstant">no</span>
@@ -535,20 +559,22 @@ highlight(row) <span class="Keyword">for</span> row, i <span class="Keyword">in<
</pre><pre class="idle">
<span class="Comment"><span class="Comment">//</span> Eat lunch.</span>
<span class="Storage">var</span> lunch;
<span class="Storage">var</span> a <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
<span class="Storage">var</span> d <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (<span class="Storage">var</span> b<span class="Keyword">=</span><span class="Number">0</span>, c<span class="Keyword">=</span>a.<span class="LibraryConstant">length</span>; b<span class="Keyword">&lt;</span>c; b<span class="Keyword">++</span>) {
<span class="Storage">var</span> food <span class="Keyword">=</span> a[b];
d[b] <span class="Keyword">=</span> food.eat();
<span class="Storage">var</span> __a <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
<span class="Storage">var</span> __d <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (<span class="Storage">var</span> __b<span class="Keyword">=</span><span class="Number">0</span>, __c<span class="Keyword">=</span>__a.<span class="LibraryConstant">length</span>; __b<span class="Keyword">&lt;</span>__c; __b<span class="Keyword">++</span>) {
<span class="Storage">var</span> food <span class="Keyword">=</span> __a[__b];
__d[__b] <span class="Keyword">=</span> food.eat();
}
lunch <span class="Keyword">=</span> d;
lunch <span class="Keyword">=</span> __d;
<span class="Comment"><span class="Comment">//</span> Zebra-stripe a table.</span>
<span class="Storage">var</span> e <span class="Keyword">=</span> table;
<span class="Keyword">for</span> (<span class="Storage">var</span> f<span class="Keyword">=</span><span class="Number">0</span>, g<span class="Keyword">=</span>e.<span class="LibraryConstant">length</span>; f<span class="Keyword">&lt;</span>g; f<span class="Keyword">++</span>) {
<span class="Storage">var</span> row <span class="Keyword">=</span> e[f];
<span class="Storage">var</span> i <span class="Keyword">=</span> f;
i <span class="Keyword">%</span> <span class="Number">2</span> <span class="Keyword">===</span> <span class="Number">0</span> ? highlight(row) : <span class="BuiltInConstant">null</span>;
<span class="Storage">var</span> __e <span class="Keyword">=</span> table;
<span class="Storage">var</span> __h <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (<span class="Storage">var</span> __f<span class="Keyword">=</span><span class="Number">0</span>, __g<span class="Keyword">=</span>__e.<span class="LibraryConstant">length</span>; __f<span class="Keyword">&lt;</span>__g; __f<span class="Keyword">++</span>) {
<span class="Storage">var</span> row <span class="Keyword">=</span> __e[__f];
<span class="Storage">var</span> i <span class="Keyword">=</span> __f;
__h[__f] <span class="Keyword">=</span> i <span class="Keyword">%</span> <span class="Number">2</span> <span class="Keyword">===</span> <span class="Number">0</span> ? highlight(row) : <span class="BuiltInConstant">null</span>;
}
__h;
</pre><br class='clear' /></div>
<p id="slice">
@@ -587,13 +613,13 @@ var three_to_six = nums.slice(3, 6 + 1);
alert(<span class="Variable">this</span>.name <span class="Keyword">+</span> <span class="String"><span class="String">&quot;</span> moved <span class="String">&quot;</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">&quot;</span>m.<span class="String">&quot;</span></span>).
<span class="FunctionName">Snake</span><span class="Keyword">:</span> <span class="FunctionArgument">name</span> <span class="Storage">=&gt;</span> <span class="Variable">this</span>.name<span class="Keyword">:</span> name.
Snake <span class="Variable">extends</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
Snake <span class="Variable">extends</span> Animal
<span class="FunctionName">Snake.prototype.move</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span>
alert(<span class="String"><span class="String">&quot;</span>Slithering...<span class="String">&quot;</span></span>)
<span class="Variable">super</span>(<span class="Number">5</span>).
<span class="FunctionName">Horse</span><span class="Keyword">:</span> <span class="FunctionArgument">name</span> <span class="Storage">=&gt;</span> <span class="Variable">this</span>.name<span class="Keyword">:</span> name.
Horse <span class="Variable">extends</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
Horse <span class="Variable">extends</span> Animal
<span class="FunctionName">Horse.prototype.move</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span>
alert(<span class="String"><span class="String">&quot;</span>Galloping...<span class="String">&quot;</span></span>)
<span class="Variable">super</span>(<span class="Number">45</span>).
@@ -616,19 +642,23 @@ tom.move()
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">name</span>;
};
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">__proto__</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
Snake.__superClass__ <span class="Keyword">=</span> Animal.<span class="LibraryConstant">prototype</span>;
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">constructor</span> = Snake;
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">&quot;</span>Slithering...<span class="String">&quot;</span></span>);
<span class="Keyword">return</span> Snake.<span class="LibraryConstant">prototype</span>.__proto__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
<span class="Keyword">return</span> Snake.__superClass__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
};
<span class="Storage">var</span> <span class="FunctionName">Horse</span> = <span class="Storage">function</span>(<span class="FunctionArgument">name</span>) {
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">name</span>;
};
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">__proto__</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
Horse.__superClass__ <span class="Keyword">=</span> Animal.<span class="LibraryConstant">prototype</span>;
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">constructor</span> = Horse;
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">&quot;</span>Galloping...<span class="String">&quot;</span></span>);
<span class="Keyword">return</span> Horse.<span class="LibraryConstant">prototype</span>.__proto__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
<span class="Keyword">return</span> Horse.__superClass__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
};
<span class="Storage">var</span> sam <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Snake</span>(<span class="String"><span class="String">&quot;</span>Sammy the Python<span class="String">&quot;</span></span>);
<span class="Storage">var</span> tom <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Horse</span>(<span class="String"><span class="String">&quot;</span>Tommy the Palomino<span class="String">&quot;</span></span>);
@@ -643,19 +673,23 @@ var Snake = function(name) {
this.name = name;
return this.name;
};
Snake.prototype.__proto__ = new Animal();
Snake.__superClass__ = Animal.prototype;
Snake.prototype = new Animal();
Snake.prototype.constructor = Snake;
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.prototype.__proto__.move.call(this, 5);
return Snake.__superClass__.move.call(this, 5);
};
var Horse = function(name) {
this.name = name;
return this.name;
};
Horse.prototype.__proto__ = new Animal();
Horse.__superClass__ = Animal.prototype;
Horse.prototype = new Animal();
Horse.prototype.constructor = Horse;
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.prototype.__proto__.move.call(this, 45);
return Horse.__superClass__.move.call(this, 45);
};
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");
@@ -761,14 +795,14 @@ to interest me on shore, I thought I would sail \
about a little and see the watery part of the \
world...";
;alert(moby_dick);'>run: moby_dick</button><br class='clear' /></div>
<h2 id="contributing">Contributing</h2>
<p>
Here's a wish list of things that would be wonderful to have in
CoffeeScript:
</p>
<ul>
<li>
A JavaScript version of the compiler, perhaps using Alessandro Warth's
@@ -783,7 +817,7 @@ world...";
should be able to compile properly.
</li>
<li>
A tutorial that introduces CoffeeScript from the ground up for folks
A tutorial that introduces CoffeeScript from the ground up for folks
without knowledge of JavaScript.
</li>
<li>
@@ -791,31 +825,57 @@ world...";
having a JavaScript version of the compiler).
</li>
<li>
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
string manipulation. Techniques for cleaning this up across the board
would be appreciated.
</li>
</ul>
<h2 id="change_log">Change Log</h2>
<p>
<b class="header" style="margin-top: 20px;">0.1.4</b>
The official CoffeeScript extension is now <tt>.coffee</tt> instead of
<tt>.cs</tt>, which properly belongs to
<a href="http://en.wikipedia.org/wiki/C_Sharp_(programming_language)">C#</a>.
Due to popular demand, you can now also use <tt>=</tt> to assign. Unlike
JavaScript, <tt>=</tt> can also be used within object literals, interchangeably
with <tt>:</tt>. Made a grammatical fix for chained function calls
like <tt>func(1)(2)(3)(4)</tt>. Inheritance and super no longer use
<tt>__proto__</tt>, so they should be IE-compatible now.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.3</b>
The <tt>coffee-script</tt> command now includes <tt>--interactive</tt>,
which launches an interactive CoffeeScript session, and <tt>--run</tt>,
which directly compiles and executes a script. Both options depend on a
working installation of Narwhal.
The <tt>aint</tt> keyword has been replaced by <tt>isnt</tt>, which goes
together a little smoother with <tt>is</tt>.
Quoted strings are now allowed as identifiers within object literals: eg.
<tt>{"5+5": 10}</tt>.
All assignment operators now use a colon: <tt>+:</tt>, <tt>-:</tt>,
<tt>*:</tt>, etc.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.2</b>
Fixed a bug with calling <tt>super()</tt> through more than one level of
Fixed a bug with calling <tt>super()</tt> through more than one level of
inheritance, with the re-addition of the <tt>extends</tt> keyword.
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
support (as a Tusk package), contributed by
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
support (as a Tusk package), contributed by
<a href="http://tlrobinson.net/">Tom Robinson</a>, including
<b>bin/cs</b> as a CoffeeScript REPL and interpreter.
New <tt>--no-wrap</tt> option to suppress the safety function
wrapper.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.1</b>
Added <tt>instanceof</tt> and <tt>typeof</tt> as operators.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.1.0</b>
Initial CoffeeScript release.

View File

@@ -1,91 +0,0 @@
var FILE = require("file");
var OS = require("os");
exports.run = function(args) {
// TODO: non-REPL
args.shift();
if (args.length) {
require(FILE.absolute(args[0]));
return;
}
while (true)
{
try {
system.stdout.write("cs> ").flush();
var result = exports.cs_eval(require("readline").readline());
if (result !== undefined)
print(result);
} catch (e) {
print(e);
}
}
}
// executes the coffee-script Ruby program to convert from CoffeeScript to Objective-J.
// eventually this will hopefully be replaced by a JavaScript program.
var coffeePath = FILE.path(module.path).dirname().dirname().join("bin", "coffee-script");
exports.compileFile = function(path) {
var coffee = OS.popen([coffeePath, "--print", path]);
if (coffee.wait() !== 0)
throw new Error("coffee compiler error");
return coffee.stdout.read();
}
exports.compile = function(source) {
var coffee = OS.popen([coffeePath, "-e"]);
coffee.stdin.write(source).flush().close();
if (coffee.wait() !== 0)
throw new Error("coffee compiler error");
return coffee.stdout.read();
}
// these two functions are equivalent to objective-j's objj_eval/make_narwhal_factory.
// implemented as a call to coffee and objj_eval/make_narwhal_factory
exports.cs_eval = function(source) {
init();
var code = exports.compile(source);
// strip the function wrapper, we add our own.
// TODO: this is very fragile
code = code.split("\n").slice(1,-2).join("\n");
return eval(code);
}
exports.make_narwhal_factory = function(path) {
init();
var code = exports.compileFile(path);
// strip the function wrapper, we add our own.
// TODO: this is very fragile
code = code.split("\n").slice(1,-2).join("\n");
var factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
if (system.engine === "rhino")
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
// eval requires parenthesis, but parenthesis break compileFunction.
else
return eval("(" + factoryText + ")");
}
var init = function() {
// make sure it's only done once
init = function(){}
}

View File

@@ -1,23 +0,0 @@
var coffeescript = null;
function CoffeeScriptLoader() {
var loader = {};
var factories = {};
loader.reload = function(topId, path) {
if (!coffeescript) coffeescript = require("coffee-script");
//print("loading objective-j: " + topId + " (" + path + ")");
factories[topId] = coffeescript.make_narwhal_factory(path);
}
loader.load = function(topId, path) {
if (!factories.hasOwnProperty(topId))
loader.reload(topId, path);
return factories[topId];
}
return loader;
};
require.loader.loaders.unshift([".cs", CoffeeScriptLoader()]);

View File

@@ -9,7 +9,7 @@ require "coffee_script/parse_error"
# Namespace for all CoffeeScript internal classes.
module CoffeeScript
VERSION = '0.1.2' # Keep in sync with the gemspec.
VERSION = '0.1.4' # Keep in sync with the gemspec.
# Compile a script (String or IO) to JavaScript.
def self.compile(script, options={})

View File

@@ -5,7 +5,7 @@
<key>name</key>
<string>comments</string>
<key>scope</key>
<string>source.cs</string>
<string>source.coffee</string>
<key>settings</key>
<dict>
<key>shellVariables</key>

View File

@@ -6,8 +6,7 @@
<string>CoffeeScript Syntax: version 1</string>
<key>fileTypes</key>
<array>
<string>cs</string>
<string>coffeescript</string>
<string>coffee</string>
</array>
<key>name</key>
<string>CoffeeScript</string>
@@ -19,22 +18,22 @@
<key>1</key>
<dict>
<key>name</key>
<string>entity.name.function.cs</string>
<string>entity.name.function.coffee</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>keyword.operator.cs</string>
<string>keyword.operator.coffee</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>variable.parameter.function.cs</string>
<string>variable.parameter.function.coffee</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>storage.type.function.cs</string>
<string>storage.type.function.coffee</string>
</dict>
</dict>
<key>comment</key>
@@ -42,7 +41,7 @@
<key>match</key>
<string>([a-zA-Z_?.$]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string>
<key>name</key>
<string>meta.function.cs</string>
<string>meta.function.coffee</string>
</dict>
<dict>
<key>captures</key>
@@ -50,12 +49,12 @@
<key>1</key>
<dict>
<key>name</key>
<string>variable.parameter.function.cs</string>
<string>variable.parameter.function.coffee</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>storage.type.function.cs</string>
<string>storage.type.function.coffee</string>
</dict>
</dict>
<key>comment</key>
@@ -63,7 +62,7 @@
<key>match</key>
<string>([a-zA-Z_?., $]*)\s*(=&gt;)</string>
<key>name</key>
<string>meta.inline.function.cs</string>
<string>meta.inline.function.coffee</string>
</dict>
<dict>
<key>captures</key>
@@ -71,12 +70,12 @@
<key>1</key>
<dict>
<key>name</key>
<string>keyword.operator.new.cs</string>
<string>keyword.operator.new.coffee</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>entity.name.type.instance.cs</string>
<string>entity.name.type.instance.coffee</string>
</dict>
</dict>
<key>match</key>
@@ -88,7 +87,7 @@
<key>match</key>
<string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?))\b</string>
<key>name</key>
<string>constant.numeric.cs</string>
<string>constant.numeric.coffee</string>
</dict>
<dict>
<key>begin</key>
@@ -98,7 +97,7 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.cs</string>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
@@ -108,18 +107,18 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.cs</string>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.single.cs</string>
<string>string.quoted.single.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.cs</string>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
@@ -131,7 +130,7 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.cs</string>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
@@ -141,18 +140,18 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.cs</string>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.cs</string>
<string>string.quoted.double.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.cs</string>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
@@ -164,7 +163,7 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.cs</string>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
@@ -174,18 +173,18 @@
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.cs</string>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.script.cs</string>
<string>string.quoted.script.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.cs</string>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
@@ -195,61 +194,61 @@
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.cs</string>
<string>punctuation.definition.comment.coffee</string>
</dict>
</dict>
<key>match</key>
<string>(#).*$\n?</string>
<key>name</key>
<string>comment.line.cs</string>
<string>comment.line.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(break|when|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|while)\b</string>
<key>name</key>
<string>keyword.control.cs</string>
<string>keyword.control.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(true|on|yes)\b</string>
<key>name</key>
<string>constant.language.boolean.true.cs</string>
<string>constant.language.boolean.true.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(false|off|no)\b</string>
<key>name</key>
<string>constant.language.boolean.false.cs</string>
<string>constant.language.boolean.false.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\bnull\b</string>
<key>name</key>
<string>constant.language.null.cs</string>
<string>constant.language.null.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(super|this|extends)\b</string>
<key>name</key>
<string>variable.language.cs</string>
<string>variable.language.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(debugger)\b</string>
<key>name</key>
<string>keyword.other.cs</string>
<string>keyword.other.coffee</string>
</dict>
<dict>
<key>match</key>
<string>!|\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|and|or|is|aint|not)\b</string>
<string>!|\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
<key>name</key>
<string>keyword.operator.cs</string>
<string>keyword.operator.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(Infinity|NaN|undefined)\b</string>
<key>name</key>
<string>constant.language.cs</string>
<string>constant.language.coffee</string>
</dict>
<dict>
<key>begin</key>
@@ -259,7 +258,7 @@
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.cs</string>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
@@ -269,18 +268,18 @@
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.cs</string>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.regexp.cs</string>
<string>string.regexp.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.cs</string>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
@@ -288,41 +287,41 @@
<key>match</key>
<string>\;</string>
<key>name</key>
<string>punctuation.terminator.statement.cs</string>
<string>punctuation.terminator.statement.coffee</string>
</dict>
<dict>
<key>match</key>
<string>,[ |\t]*</string>
<key>name</key>
<string>meta.delimiter.object.comma.cs</string>
<string>meta.delimiter.object.comma.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\.</string>
<key>name</key>
<string>meta.delimiter.method.period.cs</string>
<string>meta.delimiter.method.period.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\{|\}</string>
<key>name</key>
<string>meta.brace.curly.cs</string>
<string>meta.brace.curly.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\(|\)</string>
<key>name</key>
<string>meta.brace.round.cs</string>
<string>meta.brace.round.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\[|\]</string>
<key>name</key>
<string>meta.brace.square.cs</string>
<string>meta.brace.square.coffee</string>
</dict>
</array>
<key>scopeName</key>
<string>source.cs</string>
<string>source.coffee</string>
<key>uuid</key>
<string>5B520980-A7D5-4E10-8582-1A4C889A8DE5</string>
</dict>

View File

@@ -13,7 +13,7 @@ module CoffeeScript
coffee-script compiles CoffeeScript source files into JavaScript.
Usage:
coffee-script path/to/script.cs
coffee-script path/to/script.coffee
EOS
# Seconds to pause between checks for changed source files.
@@ -23,8 +23,10 @@ Usage:
def initialize
@mtimes = {}
parse_options
return launch_repl if @options[:interactive]
return eval_scriptlet if @options[:eval]
check_sources
return run_scripts if @options[:run]
@sources.each {|source| compile_javascript(source) }
watch_coffee_scripts if @options[:watch]
end
@@ -100,6 +102,23 @@ Usage:
puts js
end
# Use Narwhal to run an interactive CoffeeScript session.
def launch_repl
exec "narwhal lib/coffee_script/narwhal/js/launcher.js"
rescue Errno::ENOENT
puts "Error: Narwhal must be installed to use the interactive REPL."
exit(1)
end
# Use Narwhal to compile and execute CoffeeScripts.
def run_scripts
sources = @sources.join(' ')
exec "narwhal lib/coffee_script/narwhal/js/launcher.js #{sources}"
rescue Errno::ENOENT
puts "Error: Narwhal must be installed in order to execute CoffeeScripts."
exit(1)
end
# Print the tokens that the lexer generates from a source script.
def tokens(script)
puts Lexer.new.tokenize(script).inspect
@@ -134,6 +153,12 @@ Usage:
def parse_options
@options = {}
@option_parser = OptionParser.new do |opts|
opts.on('-i', '--interactive', 'run a CoffeeScript REPL (requires Narwhal)') do |i|
@options[:interactive] = true
end
opts.on('-r', '--run', 'compile and run a script (requires Narwhal)') do |r|
@options[:run] = true
end
opts.on('-o', '--output [DIR]', 'set the directory for compiled JavaScript') do |d|
@options[:output] = d
FileUtils.mkdir_p(d) unless File.exists?(d)
@@ -147,7 +172,7 @@ Usage:
opts.on('-l', '--lint', 'pipe the compiled JavaScript through JSLint') do |l|
@options[:lint] = true
end
opts.on('-e', '--eval', 'eval a little scriptlet or read from stdin') do |e|
opts.on('-e', '--eval', 'compile a cli scriptlet or read from stdin') do |e|
@options[:eval] = true
end
opts.on('-t', '--tokens', 'print the tokens that the lexer produces') do |t|
@@ -156,7 +181,7 @@ Usage:
opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
ENV['VERBOSE'] = 'true'
end
opts.on('-n', '--no-wrap', 'suppress the top-level safety function wrapper') do |n|
opts.on('-n', '--no-wrap', 'raw output, no safety wrapper or vars') do |n|
@options[:no_wrap] = true
end
opts.on_tail('--install-bundle', 'install the CoffeeScript TextMate bundle') do |i|

View File

@@ -24,20 +24,20 @@ prechigh
left '<<' '>>' '>>>'
left '&' '|' '^'
left '<=' '<' '>' '>='
right '==' '!=' IS AINT
right '==' '!=' IS ISNT
left '&&' '||' AND OR
right '-=' '+=' '/=' '*='
right '-=' '+=' '/=' '*=' '%='
right DELETE INSTANCEOF TYPEOF
left "."
left '.'
right THROW FOR IN WHILE NEW SUPER
left UNLESS IF ELSE EXTENDS
left ":" '||:' '&&:'
left ASSIGN '||=' '&&='
right RETURN
preclow
# We expect 4 shift/reduce errors for optional syntax.
# We expect 3 shift/reduce errors for optional syntax.
# There used to be 252 -- greatly improved.
expect 4
expect 3
rule
@@ -115,12 +115,13 @@ rule
# Assignment to a variable.
Assign:
Value ":" Expression { result = AssignNode.new(val[0], val[2]) }
Value ASSIGN Expression { result = AssignNode.new(val[0], val[2]) }
;
# Assignment within an object literal.
AssignObj:
IDENTIFIER ":" Expression { result = AssignNode.new(val[0], val[2], :object) }
IDENTIFIER ASSIGN Expression { result = AssignNode.new(val[0], val[2], :object) }
| STRING ASSIGN Expression { result = AssignNode.new(val[0], val[2], :object) }
| Comment { result = val[0] }
;
@@ -171,7 +172,7 @@ rule
| Expression '==' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '!=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression IS Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression AINT Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression ISNT Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '&&' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '||' Expression { result = OpNode.new(val[1], val[0], val[2]) }
@@ -182,8 +183,9 @@ rule
| Expression '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '/=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '*=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '||:' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '&&:' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '%=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '||=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| DELETE Expression { result = OpNode.new(val[0], val[1]) }
| TYPEOF Expression { result = OpNode.new(val[0], val[1]) }
@@ -257,12 +259,13 @@ rule
# Extending an object's prototype.
Extends:
Value EXTENDS Expression { result = ExtendsNode.new(val[0], val[2]) }
Value EXTENDS Value { result = ExtendsNode.new(val[0], val[2]) }
;
# A generic function invocation.
Invocation:
Value "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
| Invocation "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
;
# Calling super.
@@ -313,19 +316,23 @@ rule
;
# Array comprehensions, including guard and current index.
# Looks a little confusing, check nodes.rb for the arguments to ForNode.
For:
Expression FOR IDENTIFIER
IN PureExpression "." { result = ForNode.new(val[0], val[4], val[2], nil) }
| Expression FOR
IDENTIFIER "," IDENTIFIER
IN PureExpression "." { result = ForNode.new(val[0], val[6], val[2], nil, val[4]) }
| Expression FOR IDENTIFIER
IN PureExpression
IF Expression "." { result = ForNode.new(val[0], val[4], val[2], val[6]) }
| Expression FOR
IDENTIFIER "," IDENTIFIER
IN PureExpression
IF Expression "." { result = ForNode.new(val[0], val[6], val[2], val[8], val[4]) }
Expression FOR
ForVariables ForSource { result = ForNode.new(val[0], val[3][0], val[2][0], val[3][1], val[2][1]) }
;
# An array comprehension has variables for the current element and index.
ForVariables:
IDENTIFIER { result = val }
| IDENTIFIER "," IDENTIFIER { result = [val[0], val[2]] }
;
# The source of the array comprehension can optionally be filtered.
ForSource:
IN PureExpression "." { result = [val[1]] }
| IN PureExpression
IF Expression "." { result = [val[1], val[3]] }
;
# Switch/When blocks.

View File

@@ -8,7 +8,7 @@ module CoffeeScript
# The list of keywords passed verbatim to the parser.
KEYWORDS = ["if", "else", "then", "unless",
"true", "false", "yes", "no", "on", "off",
"and", "or", "is", "aint", "not",
"and", "or", "is", "isnt", "not",
"new", "return",
"try", "catch", "finally", "throw",
"break", "continue",
@@ -40,6 +40,9 @@ module CoffeeScript
# Tokens that always constitute the end of an expression.
EXP_END = ['}', ')', ']']
# Assignment tokens.
ASSIGN = [':', '=']
# Scan by attempting to match tokens one character at a time. Slow and steady.
def tokenize(code)
@code = code.chomp # Cleanup code by remove extra line breaks
@@ -139,7 +142,8 @@ module CoffeeScript
value ||= @chunk[0,1]
skip_following_newlines if EXP_START.include?(value)
remove_leading_newlines if EXP_END.include?(value)
token(value, value)
tag = ASSIGN.include?(value) ? :ASSIGN : value
token(tag, value)
@i += value.length
end

View File

@@ -0,0 +1,59 @@
# This (javascript) file is generated from lib/coffee_script/narwhal/coffee-script.coffee
# Executes the `coffee-script` Ruby program to convert from CoffeeScript
# to Javascript. Eventually this will hopefully happen entirely within JS.
# Require external dependencies.
OS: require('os')
File: require('file')
Readline: require('readline')
# The path to the CoffeeScript Compiler.
coffeePath: File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee-script')
# Our general-purpose error handler.
checkForErrors: coffeeProcess =>
return true if coffeeProcess.wait() is 0
system.stderr.print(coffeeProcess.stderr.read())
throw new Error("coffee-script compile error").
# Run a simple REPL, round-tripping to the CoffeeScript compiler for every
# command.
exports.run: args =>
args.shift()
return require(File.absolute(args[0])) if args.length
while true
try
system.stdout.write('cs> ').flush()
result: exports.evalCS(Readline.readline())
print(result) if result isnt undefined
catch e
print(e)...
# Compile a given CoffeeScript file into JavaScript.
exports.compileFile: path =>
coffee: OS.popen([coffeePath, "--print", "--no-wrap", path])
checkForErrors(coffee)
coffee.stdout.read().
# Compile a string of CoffeeScript into JavaScript.
exports.compile: source =>
coffee: OS.popen([coffeePath, "--eval", "--no-wrap"])
coffee.stdin.write(source).flush().close()
checkForErrors(coffee)
coffee.stdout.read().
# Evaluating a string of CoffeeScript first compiles it externally.
exports.evalCS: source =>
eval(exports.compile(source)).
# Make a factory for the CoffeeScript environment.
exports.makeNarwhalFactory: path =>
code: exports.compileFile(path)
factoryText: "function(require,exports,module,system,print){" + code + "/**/\n}"
if system.engine is "rhino"
Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null)
else
# eval requires parenthesis, but parenthesis break compileFunction.
eval("(" + factoryText + ")")..

View File

@@ -0,0 +1,65 @@
(function(){
// This (javascript) file is generated from lib/coffee_script/narwhal/coffee-script.coffee Executes the `coffee-script` Ruby program to convert from CoffeeScript
// to Javascript. Eventually this will hopefully happen entirely within JS. Require external dependencies.
var OS = require('os');
var File = require('file');
var Readline = require('readline');
// The path to the CoffeeScript Compiler.
var coffeePath = File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee-script');
// Our general-purpose error handler.
var checkForErrors = function(coffeeProcess) {
if (coffeeProcess.wait() === 0) {
return true;
}
system.stderr.print(coffeeProcess.stderr.read());
throw new Error("coffee-script compile error");
};
// Run a simple REPL, round-tripping to the CoffeeScript compiler for every
// command.
exports.run = function(args) {
args.shift();
if (args.length) {
return require(File.absolute(args[0]));
}
while (true) {
try {
system.stdout.write('cs> ').flush();
var result = exports.evalCS(Readline.readline());
if (result !== undefined) {
print(result);
}
} catch (e) {
print(e);
}
}
};
// Compile a given CoffeeScript file into JavaScript.
exports.compileFile = function(path) {
var coffee = OS.popen([coffeePath, "--print", "--no-wrap", path]);
checkForErrors(coffee);
return coffee.stdout.read();
};
// Compile a string of CoffeeScript into JavaScript.
exports.compile = function(source) {
var coffee = OS.popen([coffeePath, "--eval", "--no-wrap"]);
coffee.stdin.write(source).flush().close();
checkForErrors(coffee);
return coffee.stdout.read();
};
// Evaluating a string of CoffeeScript first compiles it externally.
exports.evalCS = function(source) {
return eval(exports.compile(source));
};
// Make a factory for the CoffeeScript environment.
exports.makeNarwhalFactory = function(path) {
var code = exports.compileFile(path);
var factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
if (system.engine === "rhino") {
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
} else {
// eval requires parenthesis, but parenthesis break compileFunction.
return eval("(" + factoryText + ")");
}
};
})();

View File

@@ -0,0 +1,3 @@
(function(){
require("coffee-script").run(system.args);
})();

View File

@@ -0,0 +1,20 @@
(function(){
// This (javascript) file is generated from lib/coffee_script/narwhal/loader.coffee
var coffeescript = null;
var factories = {
};
var loader = {
// Reload the coffee-script environment from source.
reload: function(topId, path) {
coffeescript = coffeescript || require('coffee-script');
factories[topId] = coffeescript.makeNarwhalFactory(path);
return factories[topId];
},
// Ensure that the coffee-script environment is loaded.
load: function(topId, path) {
return factories[topId] = factories[topId] || this.reload(topId, path);
}
};
require.loader.loaders.unshift([".coffee", loader]);
})();

View File

@@ -0,0 +1 @@
require("coffee-script").run(system.args)

View File

@@ -0,0 +1,19 @@
# This (javascript) file is generated from lib/coffee_script/narwhal/loader.coffee
coffeescript: null
factories: {}
loader: {
# Reload the coffee-script environment from source.
reload: topId, path =>
coffeescript ||= require('coffee-script')
factories[topId]: coffeescript.makeNarwhalFactory(path).
# Ensure that the coffee-script environment is loaded.
load: topId, path =>
factories[topId] ||= this.reload(topId, path).
}
require.loader.loaders.unshift([".coffee", loader])

View File

@@ -77,7 +77,7 @@ module CoffeeScript
# If this is the top-level Expressions, wrap everything in a safety closure.
def root_compile(o={})
indent = o[:no_wrap] ? '' : TAB
code = compile(:indent => indent, :scope => Scope.new)
code = compile(o.merge(:indent => indent, :scope => Scope.new))
code.gsub!(STRIP_TRAILING_WHITESPACE, '')
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
end
@@ -211,11 +211,12 @@ module CoffeeScript
def compile_super(args, o)
methname = o[:last_assign].sub(LEADING_DOT, '')
arg_part = args.empty? ? '' : ", #{args}"
"#{o[:proto_assign]}.prototype.__proto__.#{methname}.call(this#{arg_part})"
"#{o[:proto_assign]}.__superClass__.#{methname}.call(this#{arg_part})"
end
end
# Node to extend an object's prototype with an ancestor object.
# After goog.inherits from the Closure Library.
class ExtendsNode < Node
attr_reader :sub_object, :super_object
@@ -224,7 +225,10 @@ module CoffeeScript
end
def compile(o={})
"#{@sub_object.compile(o)}.prototype.__proto__ = #{@super_object.compile(o)}"
sub, sup = @sub_object.compile(o), @super_object.compile(o)
"#{sub}.__superClass__ = #{sup}.prototype;\n#{o[:indent]}" +
"#{sub}.prototype = new #{sup}();\n#{o[:indent]}" +
"#{sub}.prototype.constructor = #{sub}"
end
end
@@ -340,9 +344,9 @@ module CoffeeScript
return write("#{@variable}: #{@value.compile(o)}") if @context == :object
return write("#{name} = #{@value.compile(o)}#{postfix}") if @variable.properties? && !@value.custom_assign?
defined = o[:scope].find(name)
def_part = defined || @variable.properties? ? "" : "var #{name};\n#{o[:indent]}"
def_part = defined || @variable.properties? || o[:no_wrap] ? "" : "var #{name};\n#{o[:indent]}"
return write(def_part + @value.compile(o)) if @value.custom_assign?
def_part = defined ? name : "var #{name}"
def_part = defined || o[:no_wrap] ? name : "var #{name}"
val_part = @value.compile(o).sub(LEADING_VAR, '')
write("#{def_part} = #{val_part}#{postfix}")
end
@@ -357,10 +361,10 @@ module CoffeeScript
'and' => '&&',
'or' => '||',
'is' => '===',
"aint" => "!==",
'not' => '!',
"isnt" => "!==",
'not' => '!'
}
CONDITIONALS = ['||:', '&&:']
CONDITIONALS = ['||=', '&&=']
PREFIX_OPERATORS = ['typeof', 'delete']
attr_reader :operator, :first, :second
@@ -411,6 +415,7 @@ module CoffeeScript
indent = o[:indent]
o[:indent] += TAB
o.delete(:assign)
o.delete(:no_wrap)
@params.each {|id| o[:scope].find(id.to_s) }
code = @body.compile(o)
write("function(#{@params.join(', ')}) {\n#{code}\n#{indent}}")
@@ -473,6 +478,7 @@ module CoffeeScript
def compile(o={})
o = super(o)
o.delete(:return)
indent = o[:indent] + TAB
cond = @condition.compile(o.merge(:no_paren => true))
write("while (#{cond}) {\n#{@body.compile(o.merge(:indent => indent))}\n#{o[:indent]}}")
@@ -500,32 +506,28 @@ module CoffeeScript
def compile(o={})
o = super(o)
scope = o[:scope]
name_found = scope.find(@name)
index_found = @index && scope.find(@index)
svar = scope.free_variable
ivar = scope.free_variable
lvar = scope.free_variable
name_part = name_found ? @name : "var #{@name}"
index_name = @index ? (index_found ? @index : "var #{@index}") : nil
source_part = "var #{svar} = #{@source.compile(o)};"
for_part = "var #{ivar}=0, #{lvar}=#{svar}.length; #{ivar}<#{lvar}; #{ivar}++"
var_part = "\n#{o[:indent] + TAB}#{name_part} = #{svar}[#{ivar}];\n"
index_part = @index ? "#{o[:indent] + TAB}#{index_name} = #{ivar};\n" : ''
scope = o[:scope]
name_found = scope.find(@name)
index_found = @index && scope.find(@index)
svar = scope.free_variable
ivar = scope.free_variable
lvar = scope.free_variable
rvar = scope.free_variable
name_part = name_found ? @name : "var #{@name}"
index_name = @index ? (index_found ? @index : "var #{@index}") : nil
source_part = "var #{svar} = #{@source.compile(o)};"
for_part = "var #{ivar}=0, #{lvar}=#{svar}.length; #{ivar}<#{lvar}; #{ivar}++"
var_part = "\n#{o[:indent] + TAB}#{name_part} = #{svar}[#{ivar}];\n"
index_part = @index ? "#{o[:indent] + TAB}#{index_name} = #{ivar};\n" : ''
body = @body
suffix = ';'
set_result = "var #{rvar} = [];\n#{o[:indent]}"
save_result = "#{rvar}[#{ivar}] = "
return_result = rvar
set_result = ''
save_result = ''
return_result = ''
body = @body
suffix = ';'
if o[:return] || o[:assign]
rvar = scope.free_variable
set_result = "var #{rvar} = [];\n#{o[:indent]}"
save_result += "#{rvar}[#{ivar}] = "
return_result = rvar
return_result = "#{o[:assign]} = #{return_result};" if o[:assign]
return_result = "return #{return_result};" if o[:return]
return_result = "\n#{o[:indent]}#{return_result}"
return_result = "#{o[:assign]} = #{return_result}" if o[:assign]
return_result = "return #{return_result}" if o[:return]
if @filter
body = CallNode.new(ValueNode.new(LiteralNode.new(rvar), [AccessorNode.new('push')]), [@body])
body = IfNode.new(@filter, body, nil, :statement => true)
@@ -536,6 +538,7 @@ module CoffeeScript
body = IfNode.new(@filter, @body)
end
return_result = "\n#{o[:indent]}#{return_result};"
indent = o[:indent] + TAB
body = body.compile(o.merge(:indent => indent))
write("#{source_part}\n#{o[:indent]}#{set_result}for (#{for_part}) {#{var_part}#{index_part}#{indent}#{save_result}#{body}#{suffix}\n#{o[:indent]}}#{return_result}")

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ module CoffeeScript
def initialize(parent=nil)
@parent = parent
@variables = {}
@temp_variable = @parent ? @parent.temp_variable : 'a'
@temp_variable = @parent ? @parent.temp_variable : '__a'
end
# Look up a variable in lexical scope, or declare it if not found.

View File

@@ -1,9 +1,9 @@
{
"name": "coffee-script",
"lib": "lib-js",
"preload": ["coffee-script/loader"],
"lib": "lib/coffee_script/narwhal/js",
"preload": ["loader"],
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language"],
"author": "Jeremy Ashkenas",
"version": "0.1.2"
"version": "0.1.4"
}

View File

@@ -10,5 +10,5 @@ _.each: obj, iterator, context =>
else
iterator.call(context, obj[key], key, obj) for key in _.keys(obj)..
catch e
throw e if e aint breaker.
throw e if e isnt breaker.
obj.

22
test/fixtures/each.js vendored
View File

@@ -8,18 +8,22 @@
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (_.isArray(obj) || _.isArguments(obj)) {
var a = obj;
for (var b=0, c=a.length; b<c; b++) {
var item = a[b];
var i = b;
iterator.call(context, item, i, obj);
var __a = obj;
var __d = [];
for (var __b=0, __c=__a.length; __b<__c; __b++) {
var item = __a[__b];
var i = __b;
__d[__b] = iterator.call(context, item, i, obj);
}
__d;
} else {
var d = _.keys(obj);
for (var e=0, f=d.length; e<f; e++) {
var key = d[e];
iterator.call(context, obj[key], key, obj);
var __e = _.keys(obj);
var __h = [];
for (var __f=0, __g=__e.length; __f<__g; __f++) {
var key = __e[__f];
__h[__f] = iterator.call(context, obj[key], key, obj);
}
__h;
}
} catch (e) {
if (e !== breaker) {

View File

@@ -1 +1 @@
[[:COMMENT, [" The cornerstone, an each implementation.", " Handles objects implementing forEach, arrays, and raw objects."]], ["\n", "\n"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "each"], [":", ":"], [:PARAM, "obj"], [",", ","], [:PARAM, "iterator"], [",", ","], [:PARAM, "context"], ["=>", "=>"], ["\n", "\n"], [:IDENTIFIER, "index"], [":", ":"], [:NUMBER, "0"], ["\n", "\n"], [:TRY, "try"], ["\n", "\n"], [:IF, "if"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["\n", "\n"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["(", "("], [:IDENTIFIER, "iterator"], [",", ","], [:IDENTIFIER, "context"], [")", ")"], ["\n", "\n"], [:ELSE, "else"], [:IF, "if"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArray"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OR, "or"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArguments"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], ["\n", "\n"], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [:IN, "in"], [:IDENTIFIER, "obj"], [".", "."], ["\n", "\n"], [:ELSE, "else"], ["\n", "\n"], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "obj"], ["[", "["], [:IDENTIFIER, "key"], ["]", "]"], [",", ","], [:IDENTIFIER, "key"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "key"], [:IN, "in"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "keys"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [".", "."], [".", "."], ["\n", "\n"], [:CATCH, "catch"], [:IDENTIFIER, "e"], ["\n", "\n"], [:THROW, "throw"], [:IDENTIFIER, "e"], [:IF, "if"], [:IDENTIFIER, "e"], [:AINT, "aint"], [:IDENTIFIER, "breaker"], [".", "."], ["\n", "\n"], [:IDENTIFIER, "obj"], [".", "."]]
[[:COMMENT, [" The cornerstone, an each implementation.", " Handles objects implementing forEach, arrays, and raw objects."]], ["\n", "\n"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "each"], [:ASSIGN, ":"], [:PARAM, "obj"], [",", ","], [:PARAM, "iterator"], [",", ","], [:PARAM, "context"], ["=>", "=>"], ["\n", "\n"], [:IDENTIFIER, "index"], [:ASSIGN, ":"], [:NUMBER, "0"], ["\n", "\n"], [:TRY, "try"], ["\n", "\n"], [:IF, "if"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["\n", "\n"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["(", "("], [:IDENTIFIER, "iterator"], [",", ","], [:IDENTIFIER, "context"], [")", ")"], ["\n", "\n"], [:ELSE, "else"], [:IF, "if"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArray"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OR, "or"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArguments"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], ["\n", "\n"], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [:IN, "in"], [:IDENTIFIER, "obj"], [".", "."], ["\n", "\n"], [:ELSE, "else"], ["\n", "\n"], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "obj"], ["[", "["], [:IDENTIFIER, "key"], ["]", "]"], [",", ","], [:IDENTIFIER, "key"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "key"], [:IN, "in"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "keys"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [".", "."], [".", "."], ["\n", "\n"], [:CATCH, "catch"], [:IDENTIFIER, "e"], ["\n", "\n"], [:THROW, "throw"], [:IDENTIFIER, "e"], [:IF, "if"], [:IDENTIFIER, "e"], [:ISNT, "isnt"], [:IDENTIFIER, "breaker"], [".", "."], ["\n", "\n"], [:IDENTIFIER, "obj"], [".", "."]]

View File

@@ -7,18 +7,22 @@ _.each = function(obj, iterator, context) {
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (_.isArray(obj) || _.isArguments(obj)) {
var a = obj;
for (var b=0, c=a.length; b<c; b++) {
var item = a[b];
var i = b;
iterator.call(context, item, i, obj);
var __a = obj;
var __d = [];
for (var __b=0, __c=__a.length; __b<__c; __b++) {
var item = __a[__b];
var i = __b;
__d[__b] = iterator.call(context, item, i, obj);
}
__d;
} else {
var d = _.keys(obj);
for (var e=0, f=d.length; e<f; e++) {
var key = d[e];
iterator.call(context, obj[key], key, obj);
var __e = _.keys(obj);
var __h = [];
for (var __f=0, __g=__e.length; __f<__g; __f++) {
var key = __e[__f];
__h[__f] = iterator.call(context, obj[key], key, obj);
}
__h;
}
} catch (e) {
if (e !== breaker) {

View File

@@ -1,4 +1,4 @@
nums: n * n for n in [1, 2, 3] if n % 2 aint 0.
nums: n * n for n in [1, 2, 3] if n % 2 isnt 0.
result: n * 2 for n in nums.
print(result.join(',') is '2,18')

View File

@@ -1,21 +0,0 @@
(function(){
var nums;
var a = [1, 2, 3];
var d = [];
for (var b=0, c=a.length; b<c; b++) {
var n = a[b];
if (n % 2 !== 0) {
nums = d.push(n * n);
}
}
nums = d;
var result;
var e = nums;
var h = [];
for (var f=0, g=e.length; f<g; f++) {
n = e[f];
h[f] = n * 2;
}
result = h;
print(result.join(',') === '2,18');
})();

View File

@@ -1,9 +0,0 @@
(function(){
var result;
try {
result = nonexistent * missing;
} catch (error) {
result = true;
}
print(result);
})();

View File

@@ -3,17 +3,17 @@ Base.prototype.func: string =>
'zero/' + string.
FirstChild: => .
FirstChild extends new Base()
FirstChild extends Base
FirstChild.prototype.func: string =>
super('one/') + string.
SecondChild: => .
SecondChild extends new FirstChild()
SecondChild extends FirstChild
SecondChild.prototype.func: string =>
super('two/') + string.
ThirdChild: => .
ThirdChild extends new SecondChild()
ThirdChild extends SecondChild
ThirdChild.prototype.func: string =>
super('three/') + string.

View File

@@ -1,27 +0,0 @@
(function(){
var Base = function() {
};
Base.prototype.func = function(string) {
return 'zero/' + string;
};
var FirstChild = function() {
};
FirstChild.prototype.__proto__ = new Base();
FirstChild.prototype.func = function(string) {
return FirstChild.prototype.__proto__.func.call(this, 'one/') + string;
};
var SecondChild = function() {
};
SecondChild.prototype.__proto__ = new FirstChild();
SecondChild.prototype.func = function(string) {
return SecondChild.prototype.__proto__.func.call(this, 'two/') + string;
};
var ThirdChild = function() {
};
ThirdChild.prototype.__proto__ = new SecondChild();
ThirdChild.prototype.func = function(string) {
return ThirdChild.prototype.__proto__.func.call(this, 'three/') + string;
};
var result = (new ThirdChild()).func('four');
print(result === 'zero/one/two/three/four');
})();

View File

@@ -0,0 +1,5 @@
identity_wrap: x => => x..
result: identity_wrap(identity_wrap(true))()()
print(result)

View File

@@ -1,6 +0,0 @@
(function(){
var a = b = d = true;
var c = false;
var result = a ? b ? c ? false : d ? true : null : null : null;
print(result);
})();

View File

@@ -1,10 +0,0 @@
a: 5
atype: typeof a
b: "hello"
btype: typeof b
Klass: => .
k: new Klass()
print(atype is 'number' and btype is 'string' and k instanceof Klass)

View File

@@ -1,10 +0,0 @@
(function(){
var a = 5;
var atype = typeof a;
var b = "hello";
var btype = typeof b;
var Klass = function() {
};
var k = new Klass();
print(atype === 'number' && btype === 'string' && k instanceof Klass);
})();

View File

@@ -6,7 +6,7 @@ func: =>
a--.
c: {
text: b
"text": b
}
c: 'error' unless 42 > 41
@@ -16,7 +16,11 @@ func: =>
else
c.text + '---'.
c.list: let for let in c.text.split('') if let is '-'.
d = {
text = c.text
}
c.list: l for l in d.text.split('') if l is '-'.
c.single: c.list[1, 1][0].

View File

@@ -1,29 +0,0 @@
(function(){
var func = function() {
var a = 3;
var b = [];
while (a >= 0) {
b.push('o');
a--;
}
var c = {
text: b
};
if (!(42 > 41)) {
c = 'error';
}
c.text = false ? 'error' : c.text + '---';
var d = c.text.split('');
var g = [];
for (var e=0, f=d.length; e<f; e++) {
var let = d[e];
if (let === '-') {
c.list = g.push(let);
}
}
c.list = g;
c.single = c.list.slice(1, 1 + 1)[0];
return c.single;
};
print(func() === '-');
})();

View File

@@ -1,16 +0,0 @@
(function(){
var num = 10;
var result;
if (num === 5) {
result = false;
} else if (num === 'a') {
result = false;
} else if (num === 10) {
result = true;
} else if (num === 11) {
result = false;
} else {
result = false;
}
print(result);
})();

View File

@@ -3,28 +3,20 @@ require 'test_helper'
class ExecutionTest < Test::Unit::TestCase
NO_WARNINGS = /\A(0 error\(s\), 0 warning\(s\)\n)+\Z/
ALLS_WELL = /\A\n?(true\n)+\Z/
def test_execution_of_coffeescript
`bin/coffee-script test/fixtures/execution/*.cs`
sources = Dir['test/fixtures/execution/*.js'].map {|f| File.expand_path(f) }
starting_place = File.expand_path(Dir.pwd)
Dir.chdir('/Users/jashkenas/Desktop/Beauty/Code/v8')
sources.each do |source|
suceeded = `./shell #{source}`.chomp.to_sym == :true
puts "failed: #{source}" unless suceeded
assert suceeded
end
ensure
Dir.chdir(starting_place)
sources = ['test/fixtures/execution/*.coffee'].join(' ')
assert `bin/coffee-script -r #{sources}`.match(ALLS_WELL)
end
def test_lintless_coffeescript
lint_results = `bin/coffee-script -l test/fixtures/execution/*.cs`
lint_results = `bin/coffee-script -l test/fixtures/execution/*.coffee`
assert lint_results.match(NO_WARNINGS)
end
def test_lintless_examples
lint_results = `bin/coffee-script -l examples/*.cs`
lint_results = `bin/coffee-script -l examples/*.coffee`
assert lint_results.match(NO_WARNINGS)
end

View File

@@ -12,14 +12,14 @@ class LexerTest < Test::Unit::TestCase
def test_lexing_basic_assignment
code = "a: 'one'; b: [1, 2]"
assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [":", ":"],
[:STRING, "'one'"], [";", ";"], [:IDENTIFIER, "b"], [":", ":"],
assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [:ASSIGN, ":"],
[:STRING, "'one'"], [";", ";"], [:IDENTIFIER, "b"], [:ASSIGN, ":"],
["[", "["], [:NUMBER, "1"], [",", ","], [:NUMBER, "2"], ["]", "]"]]
end
def test_lexing_object_literal
code = "{one : 1}"
assert @lex.tokenize(code) == [["{", "{"], [:IDENTIFIER, "one"], [":", ":"],
assert @lex.tokenize(code) == [["{", "{"], [:IDENTIFIER, "one"], [:ASSIGN, ":"],
[:NUMBER, "1"], ["}", "}"]]
end
@@ -37,13 +37,13 @@ class LexerTest < Test::Unit::TestCase
def test_lexing_comment
code = "a: 1\n # comment\n # on two lines\nb: 2"
assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [":", ":"], [:NUMBER, "1"],
assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [:ASSIGN, ":"], [:NUMBER, "1"],
["\n", "\n"], [:COMMENT, [" comment", " on two lines"]], ["\n", "\n"],
[:IDENTIFIER, "b"], [":", ":"], [:NUMBER, "2"]]
[:IDENTIFIER, "b"], [:ASSIGN, ":"], [:NUMBER, "2"]]
end
def test_lexing
tokens = @lex.tokenize(File.read('test/fixtures/each.cs'))
tokens = @lex.tokenize(File.read('test/fixtures/each.coffee'))
assert tokens.inspect == File.read('test/fixtures/each.tokens')
end

View File

@@ -58,12 +58,12 @@ class ParserTest < Test::Unit::TestCase
end
def test_parsing_inner_comments
nodes = @par.parse(File.read('test/fixtures/inner_comments.cs'))
nodes = @par.parse(File.read('test/fixtures/inner_comments.coffee'))
assert nodes.compile == File.read('test/fixtures/inner_comments.js')
end
def test_parsing
nodes = @par.parse(File.read('test/fixtures/each.cs'))
nodes = @par.parse(File.read('test/fixtures/each.coffee'))
assign = nodes.expressions[1]
assert assign.is_a? AssignNode
assert assign.variable.literal == '_'
@@ -73,7 +73,7 @@ class ParserTest < Test::Unit::TestCase
end
def test_no_wrap
nodes = @par.parse(File.read('test/fixtures/each.cs'))
nodes = @par.parse(File.read('test/fixtures/each.coffee'))
assert nodes.compile(:no_wrap => true) == File.read('test/fixtures/each_no_wrap.js')
end