broken waypoint, but fixed line numbers with the new JS comments

This commit is contained in:
Jeremy Ashkenas 2009-12-23 19:42:18 -05:00
parent 6555473788
commit 60eabf63cf
14 changed files with 730 additions and 344 deletions

View File

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

View File

@ -0,0 +1,22 @@
# Assignment:
number: 42
opposite_day: true
# Conditions:
number: -42 if opposite_day
# Functions:
square: x => x * x.
# Arrays:
list: [1, 2, 3, 4, 5]
# Objects:
math: {
root: Math.sqrt
square: square
cube: x => x * square(x).
}
# Array comprehensions:
cubed_list: math.cube(num) for num in list.

View File

@ -2,6 +2,6 @@ try
all_hell_breaks_loose() all_hell_breaks_loose()
cats_and_dogs_living_together() cats_and_dogs_living_together()
catch error catch error
print( error ) print(error)
finally finally
clean_up(). clean_up().

View File

@ -30,31 +30,33 @@ b.header {
margin: 40px 0 5px 0; margin: 40px 0 5px 0;
font-size: 16px; font-size: 16px;
} }
table, tr, td { table {
margin: 0; padding: 0; margin: 16px 0 0 13px; padding: 0;
width: 625px;
} }
tr, td {
margin: 0; padding: 0;
}
td { td {
padding: 2px 12px 2px 0; padding: 9px 15px 9px 0;
} }
code, pre, tt { code, pre, tt {
font-family: Monaco, Consolas, "Lucida Console", monospace; font-family: Monaco, Consolas, "Lucida Console", monospace;
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
color: #555529; color: #191955;
} }
code { tt {
margin-left: 20px; background: #f8f8ff;
border: 1px solid #dedede;
font-size: 85%;
padding: 0px 0.2em;
} }
pre { pre {
border-left: 6px solid #222255;
margin-left: 13px;
padding: 3px 0 3px 12px;
font-size: 12px; font-size: 12px;
padding: 0 0 0 12px;
margin: 0;
width: 410px;
float: left;
border-left: 1px dotted #559;
}
pre:first-child {
border-left: 0;
} }
div.code { div.code {
position: relative; position: relative;
@ -68,3 +70,13 @@ div.code {
position: absolute; position: absolute;
right: 8px; bottom: 8px; right: 8px; bottom: 8px;
} }
div.code pre {
float: left;
width: 410px;
border-left: 1px dotted #559;
padding: 0 0 0 12px;
margin: 0;
}
div.code pre:first-child {
border-left: 0;
}

View File

@ -2,6 +2,7 @@
require 'uv' require 'uv'
def code_for(file, executable=false) def code_for(file, executable=false)
@stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/ @stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/
return '' unless File.exists?("documentation/js/#{file}.js")
cs = File.read("documentation/cs/#{file}.cs") cs = File.read("documentation/cs/#{file}.cs")
js = File.read("documentation/js/#{file}.js").gsub(@stripper, '') js = File.read("documentation/js/#{file}.js").gsub(@stripper, '')
cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false) cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false)
@ -30,10 +31,10 @@
<p> <p>
CoffeeScript is a little language that compiles into JavaScript. Think CoffeeScript is a little language that compiles into JavaScript. Think
of it as JavaScript's simpleminded kid brother &mdash; the same genes, of it as JavaScript's less ostentatious kid brother &mdash; the same genes,
the same accent, but a different sense of style. Apart from a handful of the same accent, but a different sense of style. Apart from a handful of
bonus goodies, statements in CoffeeScript correspond one-to-one with their bonus goodies, statements in CoffeeScript correspond one-to-one with their
JavaScript equivalent, it's just another way of saying it. equivalent in JavaScript, it's just another way of saying it.
</p> </p>
<!-- <%# code_for('intro') %>--> <!-- <%# code_for('intro') %>-->
@ -41,79 +42,163 @@
<p> <p>
<b>Disclaimer:</b> <b>Disclaimer:</b>
CoffeeScript is just for fun and seriously alpha. <i>There is no guarantee, CoffeeScript is just for fun and seriously alpha. <i>There is no guarantee,
explicit or implied, of its suitability for any purpose.</i> That said, it explicit or implied, of its suitability for any purpose.</i> That said,
compiles into pretty-printed JavaScript (the good parts) that can pass through it compiles into clean JavaScript (the good parts) that can use existing
<a href="http://www.jslint.com/">JSLint</a> warning-free. JavaScript libraries seamlessly, and can pass through
<a href="http://www.jslint.com/">JSLint</a> without warnings. The compiled
scripts are quite readable &mdash; pretty-printed, with comments
preserved intact.
</p> </p>
<h2>Table of Contents</h2> <h2>Table of Contents</h2>
<p> <p>
<i> <a href="#overview">Mini Overview</a><br />
This document is structured so that it can be read from top to bottom, <a href="#installation">Installation and Usage</a><br />
if you like. Later sections use ideas and syntax previously introduced.
</i>
</p>
<p>
<a href="#punctuation">Punctuation Primer</a><br /> <a href="#punctuation">Punctuation Primer</a><br />
<a href="#functions">Functions and Invocation</a><br /> <a href="#functions">Functions and Invocation</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#assignment">Assignment</a><br /> <a href="#assignment">Assignment</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br /> <a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br />
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br /> <a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br />
<a href="#expressions">Everything is an Expression</a><br /> <a href="#expressions">Everything is an Expression</a><br />
<a href="#while">While Loops</a><br /> <a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</a><br /> <a href="#array_comprehensions">Array Comprehensions</a><br />
<a href="#slice">Array Slice Literals</a><br /> <a href="#slice">Array Slice Literals</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a> <a href="#super">Calling Super from a Subclass</a><br />
<a href="#embedded">Embedded JavaScript</a><br /> <a href="#embedded">Embedded JavaScript</a><br />
<a href="#aliases">Aliases</a><br />
<a href="#switch">Switch/Case/Else</a><br /> <a href="#switch">Switch/Case/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br /> <a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br /> <a href="#strings">Multiline Strings</a><br />
</p> </p>
<h2 id="overview">Mini Overview</h2>
<p><i>CoffeeScript on the left, compiled JavaScript output on the right.</i></p>
<%= code_for('overview', 'cubed_list') %>
<h2 id="installation">Installation and Usage</h2>
<pre>
sudo gem install coffee-script</pre>
<p> <p>
In all of the following examples, the source CoffeeScript is provided on Installing the gem provides the <tt>coffee-script</tt> command, which can
the left, and the direct compilation into JavaScript is on the right. be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug. By default, <tt>coffee-script</tt> writes out the
JavaScript as <tt>.js</tt> files in the same directory, but output
can be customized with the following options:
</p> </p>
<div id="documentation"> <table>
<tr>
<td width="25%"><code>-o, --output [DIR]</code></td>
<td>
Write out all compiled JavaScript files into the specified directory.
</td>
</tr>
<tr>
<td><code>-w, --watch</code></td>
<td>
Watch the modification times of the named scripts, recompiling as
soon as a change occurs.
</td>
</tr>
<tr>
<td><code>-p, --print</code></td>
<td>
Instead of writing out the JavaScript as a file, print it
directly to <b>stdout</b>.
</td>
</tr>
<tr>
<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.
</td>
</tr>
<tr>
<td><code>-e, --eval</code></td>
<td>
Compile and print a little snippet of CoffeeScript directly from the
command line. For example:<br /><tt>coffee-script -e "square: x => x * x."</tt>
</td>
</tr>
<tr>
<td><code>-t, --tokens</code></td>
<td>
Instead of parsing the CoffeeScript, just lex it, and print out the
token stream: <tt>[:IDENTIFIER, "square"], [":", ":"], [:PARAM, "x"]</tt> ...
</td>
</tr>
<tr>
<td><code>-v, --verbose</code></td>
<td>
As the JavaScript is being generated, print out every step of code
generation, including lexical scope and the node in the
AST.
</td>
</tr>
</table>
<p>
<b>Examples:</b>
</p>
<pre>
coffee-script path/to/script.cs
coffee-script --watch --lint experimental.cs
coffee-script --print app/scripts/*.cs > concatenation.js</pre>
<h2>Language Reference</h2>
<p>
<i>
This document is structured so that it can be read from top to bottom,
if you like. Later sections use ideas and syntax previously introduced.
In all of the following examples, the source CoffeeScript is provided on
the left, and the direct compilation into JavaScript is on the right.
Familiarity with JavaScript is assumed, although it would certainly
be nice to have a tutorial that builds from the ground up in the future.
</i>
</p>
<p id="punctuation"> <p id="punctuation">
<b class="header">Punctuation Primer</b> <b class="header">Punctuation Primer</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. So newlines can matter, but whitespace is the line will do just as well. All other whitespace is
not otherwise significant. Instead of using curly braces (<b>{ }</b>) not significant. Instead of using curly braces <tt>{ }</tt>
to delimit blocks of code, a period (<b>.</b>) marks the end of a to delimit a block of code, use a period <tt>.</tt> to mark the end of a
function, if statement, or try/catch. function, if-statement, switch, or try/catch.
</p> </p>
<!-- <%# code_for('punctuation') %> -->
<p id="functions"> <p id="functions">
<b class="header">Functions and Invocation</b> <b class="header">Functions and Invocation</b>
Let's start with the best part, shall we? Function literals are my Let's start with the best part, shall we? Functions are defined
absolute favorite thing about CoffeeScript. by a list of parameters, an arrow, and the function body. The empty
function looks like this: <tt>=>.</tt>
</p> </p>
<%= code_for('functions', 'cube(5)') %> <%= code_for('functions', 'cube(5)') %>
<p id="objects_arrays">
<b class="header">Objects and Arrays</b>
Object and Array literals look very similar. When you spread out
each assignment on a separate line, the commas are optional.
</p>
<%= code_for('objects_and_arrays', 'song.join(",")') %>
<p>
</p>
<p id="assignment"> <p id="assignment">
<b class="header">Assignment</b> <b class="header">Assignment</b>
All assignment in CoffeeScript, whether to a variable or to an object Use a colon <tt>:</tt> to assign, as in
property, uses a colon. Equal signs are only needed for mathy things. <a href="http://json.org">JSON</a>. Equal signs are only needed for
mathy things.
</p> </p>
<%= code_for('assignment', 'greeting') %> <%= code_for('assignment', 'greeting') %>
<p>
<p id="objects_and_arrays">
<b class="header">Objects and Arrays</b>
Object and Array literals look very similar to their JavaScript cousins.
When you spread out each assignment on a separate line, the commas are
optional. In this way, assigning object properties looks the same as
assigning local variables.
</p> </p>
<%= code_for('objects_and_arrays', 'song.join(",")') %>
<p id="lexical_scope"> <p id="lexical_scope">
<b class="header">Lexical Scoping and Variable Safety</b> <b class="header">Lexical Scoping and Variable Safety</b>
@ -123,33 +208,47 @@
</p> </p>
<%= code_for('scope', 'new_num') %> <%= code_for('scope', 'new_num') %>
<p> <p>
Notice how the variables are declared with <i>var</i> the first time Notice how the variables are declared with <tt>var</tt> the first time
they appear. The second reference of <b>num</b>, within the function, they appear. The second reference of <b>num</b>, within the function,
is not redeclared because <b>num</b> is still in scope. As opposed is not redeclared because <b>num</b> is still in scope. As opposed
to the second <b>new_num</b>, in the last line. to the second <b>new_num</b>, in the last line.
</p> </p>
<p>
Although suppressed within this documentation, all
CoffeeScript output is wrapped in an anonymous function:
<tt>(function(){ ... })();</tt> This safety wrapper, combined with the
automatic generation of the <tt>var</tt> keyword, make it exceedingly difficult
to pollute the global namespace by accident.
</p>
<p id="conditionals"> <p id="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b> <b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
If/else statements can be written without the use of parenthesis and
curly brackets. As with functions and other block expressions, conditionals
are closed with periods. No period is necessary when using the single-line
postfix form, with the <tt>if</tt> at the end.
</p> </p>
<%= code_for('conditionals') %> <%= code_for('conditionals') %>
<p> <p>
CoffeeScript includes the conditional assignment operators: <tt>||:</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;:</tt>, which will only replace the value of
truthy variables.
</p> </p>
<p id="expressions"> <p id="expressions">
<b class="header">Everything is an Expression</b> <b class="header">Everything is an Expression (at least, as much as possible)</b>
You might have noticed how even though we don't add return statements You might have noticed how even though we don't add return statements
to CoffeScript functions, they nonetheless return their final value. to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that every little language The CoffeeScript compiler tries to make sure that all statements in the
construct can be used as an expression. language can be used as expressions. Watch how the <tt>return</tt> gets
pushed down into each possible branch of execution, in the function
below.
</p> </p>
<%= code_for('expressions', 'eldest') %> <%= code_for('expressions', 'eldest') %>
<p> <p>
When compiling a function definition, CoffeeScript tries to push down The same mechanism is used to push down assignment statements, switch
the return statement to each of the potential final lines of the function. statements, and if-elses (although the ternary operator is preferred).
It uses the same mechanism to push down assignment statements. If statement
are compiled into ternary operators when possible, so that they can be used
as expressions.
</p> </p>
<p id="while"> <p id="while">
@ -157,30 +256,40 @@
The only low-level loop that CoffeeScript provides is the while loop. The only low-level loop that CoffeeScript provides is the while loop.
</p> </p>
<%= code_for('while') %> <%= code_for('while') %>
<p>
Other JavaScript loops, such as <b>for</b> loops and <b>do-while</b> loops
can be mimicked by variations on <b>while</b>, but the hope is that you
won't need to do that with CoffeeScript, either because you're using
<b>each</b> (<b>forEach</b>) style iterators, or...
</p>
<p id="array_comprehensions"> <p id="array_comprehensions">
<b class="header">Array Comprehensions</b> <b class="header">Array Comprehensions</b>
Most of your looping needs should be handled by array comprehensions. For your looping needs, CoffeeScript provides array comprehensions
They replace (and compile into) for loops, handling similar to Python's. They replace (and compile into) <b>for</b> loops, with
<b>each</b>/<b>forEach</b> style loops, as well as <b>select</b>/<b>filter</b>. optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned Unlike for loops, array comprehensions are expressions, and can be returned
and assigned. and assigned. They should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
</p> </p>
<%= code_for('array_comprehensions') %> <%= code_for('array_comprehensions') %>
<p id="slice"> <p id="slice">
<b class="header">Array Slice Literals</b> <b class="header">Array Slice Literals</b>
CoffeeScript includes a literal syntax for extracting slices of arrays. CoffeeScript includes syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and The first argument is the index of the first element in the slice, and
the second is the index of the last one. the second is the index of the last one.
</p> </p>
<%= code_for('slices', 'three_to_six') %> <%= code_for('slices', 'three_to_six') %>
<p id="inheritance"> <p id="super">
<b class="header">Inheritance, and Calling Super from a Subclass</b> <b class="header">Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a JavaScript's prototypal inheritance has always been a bit of a
brain-bender, with a whole family tree of libraries (Base2, Prototype brain-bender, with a whole family tree of libraries that provide a cleaner
). syntax for classical inheritance on top of JavaScript's prototypes:
<a href="http://code.google.com/p/base2/">Base2</a>,
<a href="http://prototypejs.org/">Prototype.js</a>,
<a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc.
</p> </p>
<%= code_for('super', true) %> <%= code_for('super', true) %>
@ -191,6 +300,22 @@
</p> </p>
<%= code_for('embedded', true) %> <%= code_for('embedded', true) %>
<p id="aliases">
<b class="header">Aliases</b>
Because the <tt>==</tt> operator frequently causes undesirable coercion,
is intransitive, and has a different meaning than in other languages,
CoffeeScript compiles <tt>==</tt> into <tt>===</tt>, and <tt>!=</tt> into
<tt>!==</tt>.
</p>
<p>
<tt>is</tt> also compiles into <tt>===</tt>,
and <tt>aint</tt> into <tt>!==</tt>.
</p>
<p>
</p>
<!-- <%# code_for('punctuation') %> -->
<p id="switch"> <p id="switch">
<b class="header">Switch/Case/Else</b> <b class="header">Switch/Case/Else</b>
Switch statements in JavaScript are fundamentally broken. You can only Switch statements in JavaScript are fundamentally broken. You can only
@ -217,7 +342,5 @@
</div> </div>
</div>
</body> </body>
</html> </html>

View File

@ -3,11 +3,7 @@
if (student.excellent_work) { if (student.excellent_work) {
return "A+"; return "A+";
} else if (student.okay_stuff) { } else if (student.okay_stuff) {
return if (student.tried_hard) { return student.tried_hard ? "B" : "B-";
return "B";
} else {
return "B-";
};
} else { } else {
return "C"; return "C";
} }

View File

@ -0,0 +1,33 @@
(function(){
// Assignment:
var number = 42;
var opposite_day = true;
// Conditions:
if (opposite_day) {
number = -42;
}
// Functions:
var square = function(x) {
return x * x;
};
// Arrays:
var list = [1, 2, 3, 4, 5];
// Objects:
var math = {
root: Math.sqrt,
square: square,
cube: function(x) {
return x * square(x);
}
};
// 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);
}
cubed_list = d;
})();

View File

@ -4,9 +4,7 @@
} else if (day === "Wednesday") { } else if (day === "Wednesday") {
go_to_the_park(); go_to_the_park();
} else if (day === "Saturday") { } else if (day === "Saturday") {
if (day === bingo_day) { day === bingo_day ? go_to_bingo() : null;
go_to_bingo();
};
} else if (day === "Sunday") { } else if (day === "Sunday") {
go_to_church(); go_to_church();
} else { } else {

View File

@ -62,8 +62,8 @@ race: =>
race(). race().
# Conditional assignment: # Conditional assignment:
good ||= evil good ||: evil
wine &&= cheese wine &&: cheese
# Nested property access and calls. # Nested property access and calls.
((moon.turn(360))).shapes[3].move({x: 45, y: 30}).position['top'].offset('x') ((moon.turn(360))).shapes[3].move({x: 45, y: 30}).position['top'].offset('x')

View File

@ -17,10 +17,10 @@
<p> <p>
CoffeeScript is a little language that compiles into JavaScript. Think CoffeeScript is a little language that compiles into JavaScript. Think
of it as JavaScript's simpleminded kid brother &mdash; the same genes, of it as JavaScript's less ostentatious kid brother &mdash; the same genes,
the same accent, but a different sense of style. Apart from a handful of the same accent, but a different sense of style. Apart from a handful of
bonus goodies, statements in CoffeeScript correspond one-to-one with their bonus goodies, statements in CoffeeScript correspond one-to-one with their
JavaScript equivalent, it's just another way of saying it. equivalent in JavaScript, it's just another way of saying it.
</p> </p>
<!-- --> <!-- -->
@ -28,59 +28,228 @@
<p> <p>
<b>Disclaimer:</b> <b>Disclaimer:</b>
CoffeeScript is just for fun and seriously alpha. <i>There is no guarantee, CoffeeScript is just for fun and seriously alpha. <i>There is no guarantee,
explicit or implied, of its suitability for any purpose.</i> That said, it explicit or implied, of its suitability for any purpose.</i> That said,
compiles into pretty-printed JavaScript (the good parts) that can pass through it compiles into clean JavaScript (the good parts) that can use existing
<a href="http://www.jslint.com/">JSLint</a> warning-free. JavaScript libraries seamlessly, and can pass through
<a href="http://www.jslint.com/">JSLint</a> without warnings. The compiled
scripts are quite readable &mdash; pretty-printed, with comments
preserved intact.
</p> </p>
<h2>Table of Contents</h2> <h2>Table of Contents</h2>
<p> <p>
<i> <a href="#overview">Mini Overview</a><br />
This document is structured so that it can be read from top to bottom, <a href="#installation">Installation and Usage</a><br />
if you like. Later sections use ideas and syntax previously introduced.
</i>
</p>
<p>
<a href="#punctuation">Punctuation Primer</a><br /> <a href="#punctuation">Punctuation Primer</a><br />
<a href="#functions">Functions and Invocation</a><br /> <a href="#functions">Functions and Invocation</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#assignment">Assignment</a><br /> <a href="#assignment">Assignment</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br /> <a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br />
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br /> <a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br />
<a href="#expressions">Everything is an Expression</a><br /> <a href="#expressions">Everything is an Expression</a><br />
<a href="#while">While Loops</a><br /> <a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</a><br /> <a href="#array_comprehensions">Array Comprehensions</a><br />
<a href="#slice">Array Slice Literals</a><br /> <a href="#slice">Array Slice Literals</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a> <a href="#super">Calling Super from a Subclass</a><br />
<a href="#embedded">Embedded JavaScript</a><br /> <a href="#embedded">Embedded JavaScript</a><br />
<a href="#aliases">Aliases</a><br />
<a href="#switch">Switch/Case/Else</a><br /> <a href="#switch">Switch/Case/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br /> <a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br /> <a href="#strings">Multiline Strings</a><br />
</p> </p>
<h2 id="overview">Mini Overview</h2>
<p><i>CoffeeScript on the left, compiled JavaScript output on the right.</i></p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Assignment:</span>
number<span class="Keyword">:</span> <span class="Number">42</span>
opposite_day<span class="Keyword">:</span> <span class="BuiltInConstant">true</span>
<span class="Comment"><span class="Comment">#</span> Conditions:</span>
number<span class="Keyword">:</span> <span class="Keyword">-</span><span class="Number">42</span> <span class="Keyword">if</span> opposite_day
<span class="Comment"><span class="Comment">#</span> Functions:</span>
<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.
<span class="Comment"><span class="Comment">#</span> Arrays:</span>
list<span class="Keyword">:</span> [<span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>]
<span class="Comment"><span class="Comment">#</span> Objects:</span>
math<span class="Keyword">:</span> {
root<span class="Keyword">:</span> Math.sqrt
square<span class="Keyword">:</span> square
<span class="FunctionName">cube</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> x <span class="Keyword">*</span> square(x).
}
<span class="Comment"><span class="Comment">#</span> Array comprehensions:</span>
cubed_list<span class="Keyword">:</span> math.cube(num) <span class="Keyword">for</span> num <span class="Keyword">in</span> list.
</pre><pre class="idle">
<span class="Comment"><span class="Comment">//</span> Assignment:</span>
<span class="Storage">var</span> number <span class="Keyword">=</span> <span class="Number">42</span>;
<span class="Storage">var</span> opposite_day <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>;
<span class="Comment"><span class="Comment">//</span> Conditions:</span>
<span class="Keyword">if</span> (opposite_day) {
number <span class="Keyword">=</span> <span class="Keyword">-</span><span class="Number">42</span>;
}
<span class="Comment"><span class="Comment">//</span> Functions:</span>
<span class="Storage">var</span> <span class="FunctionName">square</span> = <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
<span class="Keyword">return</span> x <span class="Keyword">*</span> x;
};
<span class="Comment"><span class="Comment">//</span> Arrays:</span>
<span class="Storage">var</span> list <span class="Keyword">=</span> [<span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>];
<span class="Comment"><span class="Comment">//</span> Objects:</span>
<span class="Storage">var</span> math <span class="Keyword">=</span> {
root: <span class="LibraryClassType">Math</span>.sqrt,
square: square,
<span class="FunctionName">cube</span>: <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
<span class="Keyword">return</span> x <span class="Keyword">*</span> square(x);
}
};
<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);
}
cubed_list <span class="Keyword">=</span> d;
</pre><button onclick='javascript:
// Assignment:
var number = 42;
var opposite_day = true;
// Conditions:
if (opposite_day) {
number = -42;
}
// Functions:
var square = function(x) {
return x * x;
};
// Arrays:
var list = [1, 2, 3, 4, 5];
// Objects:
var math = {
root: Math.sqrt,
square: square,
cube: function(x) {
return x * square(x);
}
};
// 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);
}
cubed_list = d;
;alert(cubed_list);'>run: cubed_list</button><br class='clear' /></div>
<h2 id="installation">Installation and Usage</h2>
<pre>
sudo gem install coffee-script</pre>
<p> <p>
In all of the following examples, the source CoffeeScript is provided on Installing the gem provides the <tt>coffee-script</tt> command, which can
the left, and the direct compilation into JavaScript is on the right. be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug. By default, <tt>coffee-script</tt> writes out the
JavaScript as <tt>.js</tt> files in the same directory, but output
can be customized with the following options:
</p> </p>
<div id="documentation"> <table>
<tr>
<td width="25%"><code>-o, --output [DIR]</code></td>
<td>
Write out all compiled JavaScript files into the specified directory.
</td>
</tr>
<tr>
<td><code>-w, --watch</code></td>
<td>
Watch the modification times of the named scripts, recompiling as
soon as a change occurs.
</td>
</tr>
<tr>
<td><code>-p, --print</code></td>
<td>
Instead of writing out the JavaScript as a file, print it
directly to <b>stdout</b>.
</td>
</tr>
<tr>
<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.
</td>
</tr>
<tr>
<td><code>-e, --eval</code></td>
<td>
Compile and print a little snippet of CoffeeScript directly from the
command line. For example:<br /><tt>coffee-script -e "square: x => x * x."</tt>
</td>
</tr>
<tr>
<td><code>-t, --tokens</code></td>
<td>
Instead of parsing the CoffeeScript, just lex it, and print out the
token stream: <tt>[:IDENTIFIER, "square"], [":", ":"], [:PARAM, "x"]</tt> ...
</td>
</tr>
<tr>
<td><code>-v, --verbose</code></td>
<td>
As the JavaScript is being generated, print out every step of code
generation, including lexical scope and the node in the
AST.
</td>
</tr>
</table>
<p>
<b>Examples:</b>
</p>
<pre>
coffee-script path/to/script.cs
coffee-script --watch --lint experimental.cs
coffee-script --print app/scripts/*.cs > concatenation.js</pre>
<h2>Language Reference</h2>
<p>
<i>
This document is structured so that it can be read from top to bottom,
if you like. Later sections use ideas and syntax previously introduced.
In all of the following examples, the source CoffeeScript is provided on
the left, and the direct compilation into JavaScript is on the right.
Familiarity with JavaScript is assumed, although it would certainly
be nice to have a tutorial that builds from the ground up in the future.
</i>
</p>
<p id="punctuation"> <p id="punctuation">
<b class="header">Punctuation Primer</b> <b class="header">Punctuation Primer</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. So newlines can matter, but whitespace is the line will do just as well. All other whitespace is
not otherwise significant. Instead of using curly braces (<b>{ }</b>) not significant. Instead of using curly braces <tt>{ }</tt>
to delimit blocks of code, a period (<b>.</b>) marks the end of a to delimit a block of code, use a period <tt>.</tt> to mark the end of a
function, if statement, or try/catch. function, if-statement, switch, or try/catch.
</p> </p>
<!-- -->
<p id="functions"> <p id="functions">
<b class="header">Functions and Invocation</b> <b class="header">Functions and Invocation</b>
Let's start with the best part, shall we? Function literals are my Let's start with the best part, shall we? Functions are defined
absolute favorite thing about CoffeeScript. by a list of parameters, an arrow, and the function body. The empty
function looks like this: <tt>=>.</tt>
</p> </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. <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.
<span class="FunctionName">cube</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> square(x) <span class="Keyword">*</span> x. <span class="FunctionName">cube</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> square(x) <span class="Keyword">*</span> x.
@ -98,10 +267,26 @@ var cube = function(x) {
}; };
;alert(cube(5));'>run: cube(5)</button><br class='clear' /></div> ;alert(cube(5));'>run: cube(5)</button><br class='clear' /></div>
<p id="objects_arrays"> <p id="assignment">
<b class="header">Assignment</b>
Use a colon <tt>:</tt> to assign, as in
<a href="http://json.org">JSON</a>. Equal signs are only needed for
mathy things.
</p>
<div class='code'><pre class="idle">greeting<span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Hello CoffeeScript<span class="String">&quot;</span></span>
difficulty<span class="Keyword">:</span> <span class="Number">0.5</span>
</pre><pre class="idle"><span class="Storage">var</span> greeting <span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>Hello CoffeeScript<span class="String">&quot;</span></span>;
<span class="Storage">var</span> difficulty <span class="Keyword">=</span> <span class="Number">0.5</span>;
</pre><button onclick='javascript: var greeting = "Hello CoffeeScript";
var difficulty = 0.5;
;alert(greeting);'>run: greeting</button><br class='clear' /></div>
<p id="objects_and_arrays">
<b class="header">Objects and Arrays</b> <b class="header">Objects and Arrays</b>
Object and Array literals look very similar. When you spread out Object and Array literals look very similar to their JavaScript cousins.
each assignment on a separate line, the commas are optional. When you spread out each assignment on a separate line, the commas are
optional. In this way, assigning object properties looks the same as
assigning local variables.
</p> </p>
<div class='code'><pre class="idle">song<span class="Keyword">:</span> [<span class="String"><span class="String">&quot;</span>do<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>re<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>mi<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>fa<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>so<span class="String">&quot;</span></span>] <div class='code'><pre class="idle">song<span class="Keyword">:</span> [<span class="String"><span class="String">&quot;</span>do<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>re<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>mi<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>fa<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>so<span class="String">&quot;</span></span>]
ages<span class="Keyword">:</span> { ages<span class="Keyword">:</span> {
@ -122,23 +307,6 @@ var ages = {
tim: 11 tim: 11
}; };
;alert(song.join(","));'>run: song.join(",")</button><br class='clear' /></div> ;alert(song.join(","));'>run: song.join(",")</button><br class='clear' /></div>
<p>
</p>
<p id="assignment">
<b class="header">Assignment</b>
All assignment in CoffeeScript, whether to a variable or to an object
property, uses a colon. Equal signs are only needed for mathy things.
</p>
<div class='code'><pre class="idle">greeting<span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Hello CoffeeScript<span class="String">&quot;</span></span>
difficulty<span class="Keyword">:</span> <span class="Number">0.5</span>
</pre><pre class="idle"><span class="Storage">var</span> greeting <span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>Hello CoffeeScript<span class="String">&quot;</span></span>;
<span class="Storage">var</span> difficulty <span class="Keyword">=</span> <span class="Number">0.5</span>;
</pre><button onclick='javascript: var greeting = "Hello CoffeeScript";
var difficulty = 0.5;
;alert(greeting);'>run: greeting</button><br class='clear' /></div>
<p>
</p>
<p id="lexical_scope"> <p id="lexical_scope">
<b class="header">Lexical Scoping and Variable Safety</b> <b class="header">Lexical Scoping and Variable Safety</b>
@ -167,14 +335,25 @@ var change_numbers = function() {
var new_num = change_numbers(); var new_num = change_numbers();
;alert(new_num);'>run: new_num</button><br class='clear' /></div> ;alert(new_num);'>run: new_num</button><br class='clear' /></div>
<p> <p>
Notice how the variables are declared with <i>var</i> the first time Notice how the variables are declared with <tt>var</tt> the first time
they appear. The second reference of <b>num</b>, within the function, they appear. The second reference of <b>num</b>, within the function,
is not redeclared because <b>num</b> is still in scope. As opposed is not redeclared because <b>num</b> is still in scope. As opposed
to the second <b>new_num</b>, in the last line. to the second <b>new_num</b>, in the last line.
</p> </p>
<p>
Although suppressed within this documentation, all
CoffeeScript output is wrapped in an anonymous function:
<tt>(function(){ ... })();</tt> This safety wrapper, combined with the
automatic generation of the <tt>var</tt> keyword, make it exceedingly difficult
to pollute the global namespace by accident.
</p>
<p id="conditionals"> <p id="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b> <b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
If/else statements can be written without the use of parenthesis and
curly brackets. As with functions and other block expressions, conditionals
are closed with periods. No period is necessary when using the single-line
postfix form, with the <tt>if</tt> at the end.
</p> </p>
<div class='code'><pre class="idle">mood<span class="Keyword">:</span> greatly_improved <span class="Keyword">if</span> singing <div class='code'><pre class="idle">mood<span class="Keyword">:</span> greatly_improved <span class="Keyword">if</span> singing
@ -197,14 +376,20 @@ 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(); expensive <span class="Keyword">=</span> expensive <span class="Keyword">||</span> do_the_math();
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
<p> <p>
CoffeeScript includes the conditional assignment operators: <tt>||:</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;:</tt>, which will only replace the value of
truthy variables.
</p> </p>
<p id="expressions"> <p id="expressions">
<b class="header">Everything is an Expression</b> <b class="header">Everything is an Expression (at least, as much as possible)</b>
You might have noticed how even though we don't add return statements You might have noticed how even though we don't add return statements
to CoffeScript functions, they nonetheless return their final value. to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that every little language The CoffeeScript compiler tries to make sure that all statements in the
construct can be used as an expression. language can be used as expressions. Watch how the <tt>return</tt> gets
pushed down into each possible branch of execution, in the function
below.
</p> </p>
<div class='code'><pre class="idle"><span class="FunctionName">grade</span><span class="Keyword">:</span> <span class="FunctionArgument">student</span> <span class="Storage">=&gt;</span> <div class='code'><pre class="idle"><span class="FunctionName">grade</span><span class="Keyword">:</span> <span class="FunctionArgument">student</span> <span class="Storage">=&gt;</span>
<span class="Keyword">if</span> student.excellent_work <span class="Keyword">if</span> student.excellent_work
@ -219,11 +404,7 @@ eldest<span class="Keyword">:</span> <span class="Keyword">if</span> <span class
<span class="Keyword">if</span> (student.excellent_work) { <span class="Keyword">if</span> (student.excellent_work) {
<span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>A+<span class="String">&quot;</span></span>; <span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>A+<span class="String">&quot;</span></span>;
} <span class="Keyword">else</span> <span class="Keyword">if</span> (student.okay_stuff) { } <span class="Keyword">else</span> <span class="Keyword">if</span> (student.okay_stuff) {
<span class="Keyword">return</span> <span class="Keyword">if</span> (student.tried_hard) { <span class="Keyword">return</span> student.tried_hard ? <span class="String"><span class="String">&quot;</span>B<span class="String">&quot;</span></span> : <span class="String"><span class="String">&quot;</span>B-<span class="String">&quot;</span></span>;
<span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>B<span class="String">&quot;</span></span>;
} <span class="Keyword">else</span> {
<span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>B-<span class="String">&quot;</span></span>;
};
} <span class="Keyword">else</span> { } <span class="Keyword">else</span> {
<span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>C<span class="String">&quot;</span></span>; <span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>C<span class="String">&quot;</span></span>;
} }
@ -233,11 +414,7 @@ eldest<span class="Keyword">:</span> <span class="Keyword">if</span> <span class
if (student.excellent_work) { if (student.excellent_work) {
return "A+"; return "A+";
} else if (student.okay_stuff) { } else if (student.okay_stuff) {
return if (student.tried_hard) { return student.tried_hard ? "B" : "B-";
return "B";
} else {
return "B-";
};
} else { } else {
return "C"; return "C";
} }
@ -245,11 +422,8 @@ eldest<span class="Keyword">:</span> <span class="Keyword">if</span> <span class
var eldest = 24 > 21 ? "Liz" : "Ike"; var eldest = 24 > 21 ? "Liz" : "Ike";
;alert(eldest);'>run: eldest</button><br class='clear' /></div> ;alert(eldest);'>run: eldest</button><br class='clear' /></div>
<p> <p>
When compiling a function definition, CoffeeScript tries to push down The same mechanism is used to push down assignment statements, switch
the return statement to each of the potential final lines of the function. statements, and if-elses (although the ternary operator is preferred).
It uses the same mechanism to push down assignment statements. If statement
are compiled into ternary operators when possible, so that they can be used
as expressions.
</p> </p>
<p id="while"> <p id="while">
@ -269,14 +443,21 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
buy(); buy();
} }
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
<p>
Other JavaScript loops, such as <b>for</b> loops and <b>do-while</b> loops
can be mimicked by variations on <b>while</b>, but the hope is that you
won't need to do that with CoffeeScript, either because you're using
<b>each</b> (<b>forEach</b>) style iterators, or...
</p>
<p id="array_comprehensions"> <p id="array_comprehensions">
<b class="header">Array Comprehensions</b> <b class="header">Array Comprehensions</b>
Most of your looping needs should be handled by array comprehensions. For your looping needs, CoffeeScript provides array comprehensions
They replace (and compile into) for loops, handling similar to Python's. They replace (and compile into) <b>for</b> loops, with
<b>each</b>/<b>forEach</b> style loops, as well as <b>select</b>/<b>filter</b>. optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned Unlike for loops, array comprehensions are expressions, and can be returned
and assigned. and assigned. They should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
</p> </p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span> <div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
lunch<span class="Keyword">:</span> food.eat() <span class="Keyword">for</span> food <span class="Keyword">in</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>]. lunch<span class="Keyword">:</span> food.eat() <span class="Keyword">for</span> food <span class="Keyword">in</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>].
@ -304,7 +485,7 @@ lunch <span class="Keyword">=</span> d;
<p id="slice"> <p id="slice">
<b class="header">Array Slice Literals</b> <b class="header">Array Slice Literals</b>
CoffeeScript includes a literal syntax for extracting slices of arrays. CoffeeScript includes syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and The first argument is the index of the first element in the slice, and
the second is the index of the last one. the second is the index of the last one.
</p> </p>
@ -316,11 +497,14 @@ three_to_six<span class="Keyword">:</span> nums[<span class="Number">3</span>, <
var three_to_six = nums.slice(3, 6 + 1); var three_to_six = nums.slice(3, 6 + 1);
;alert(three_to_six);'>run: three_to_six</button><br class='clear' /></div> ;alert(three_to_six);'>run: three_to_six</button><br class='clear' /></div>
<p id="inheritance"> <p id="super">
<b class="header">Inheritance, and Calling Super from a Subclass</b> <b class="header">Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a JavaScript's prototypal inheritance has always been a bit of a
brain-bender, with a whole family tree of libraries (Base2, Prototype brain-bender, with a whole family tree of libraries that provide a cleaner
). syntax for classical inheritance on top of JavaScript's prototypes:
<a href="http://code.google.com/p/base2/">Base2</a>,
<a href="http://prototypejs.org/">Prototype.js</a>,
<a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc.
</p> </p>
<div class='code'><pre class="idle"><span class="FunctionName">Animal</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> . <div class='code'><pre class="idle"><span class="FunctionName">Animal</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> .
<span class="FunctionName">Animal.prototype.move</span><span class="Keyword">:</span> <span class="FunctionArgument">meters</span> <span class="Storage">=&gt;</span> <span class="FunctionName">Animal.prototype.move</span><span class="Keyword">:</span> <span class="FunctionArgument">meters</span> <span class="Storage">=&gt;</span>
@ -417,6 +601,22 @@ if (10 > 9) {
} }
;'>run</button><br class='clear' /></div> ;'>run</button><br class='clear' /></div>
<p id="aliases">
<b class="header">Aliases</b>
Because the <tt>==</tt> operator frequently causes undesirable coercion,
is intransitive, and has a different meaning than in other languages,
CoffeeScript compiles <tt>==</tt> into <tt>===</tt>, and <tt>!=</tt> into
<tt>!==</tt>.
</p>
<p>
<tt>is</tt> also compiles into <tt>===</tt>,
and <tt>aint</tt> into <tt>!==</tt>.
</p>
<p>
</p>
<!-- -->
<p id="switch"> <p id="switch">
<b class="header">Switch/Case/Else</b> <b class="header">Switch/Case/Else</b>
Switch statements in JavaScript are fundamentally broken. You can only Switch statements in JavaScript are fundamentally broken. You can only
@ -438,9 +638,7 @@ if (10 > 9) {
} <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Wednesday<span class="String">&quot;</span></span>) { } <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Wednesday<span class="String">&quot;</span></span>) {
go_to_the_park(); go_to_the_park();
} <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Saturday<span class="String">&quot;</span></span>) { } <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Saturday<span class="String">&quot;</span></span>) {
<span class="Keyword">if</span> (day <span class="Keyword">===</span> bingo_day) { day <span class="Keyword">===</span> bingo_day ? go_to_bingo() : <span class="BuiltInConstant">null</span>;
go_to_bingo();
};
} <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Sunday<span class="String">&quot;</span></span>) { } <span class="Keyword">else</span> <span class="Keyword">if</span> (day <span class="Keyword">===</span> <span class="String"><span class="String">&quot;</span>Sunday<span class="String">&quot;</span></span>) {
go_to_church(); go_to_church();
} <span class="Keyword">else</span> { } <span class="Keyword">else</span> {
@ -457,7 +655,7 @@ if (10 > 9) {
all_hell_breaks_loose() all_hell_breaks_loose()
cats_and_dogs_living_together() cats_and_dogs_living_together()
<span class="Keyword">catch</span> error <span class="Keyword">catch</span> error
print( error ) print(error)
<span class="Keyword">finally</span> <span class="Keyword">finally</span>
clean_up(). clean_up().
</pre><pre class="idle"><span class="Keyword">try</span> { </pre><pre class="idle"><span class="Keyword">try</span> {
@ -490,7 +688,5 @@ if (10 > 9) {
</div> </div>
</div>
</body> </body>
</html> </html>

View File

@ -41,12 +41,13 @@ Usage:
# Compiles (or partially compiles) the source CoffeeScript file, returning # Compiles (or partially compiles) the source CoffeeScript file, returning
# the desired JS, tokens, or lint results. # the desired JS, tokens, or lint results.
def compile_javascript(source) def compile_javascript(source)
return tokens(source) if @options[:tokens] script = File.read(source)
contents = compile(source) return tokens(script) if @options[:tokens]
return unless contents js = compile(script, source)
return puts(contents) if @options[:print] return unless js
return lint(contents) if @options[:lint] return puts(js) if @options[:print]
File.open(path_for(source), 'w+') {|f| f.write(contents) } return lint(js) if @options[:lint]
File.open(path_for(source), 'w+') {|f| f.write(js) }
end end
# Spins up a watcher thread to keep track of the modification times of the # Spins up a watcher thread to keep track of the modification times of the
@ -92,18 +93,22 @@ Usage:
# Eval a little piece of CoffeeScript directly from the command line. # Eval a little piece of CoffeeScript directly from the command line.
def eval_scriptlet def eval_scriptlet
puts CoffeeScript.compile(@sources.join(' ')) script = @sources.join(' ')
return tokens(script) if @options[:tokens]
js = compile(script)
return lint(js) if @options[:lint]
puts js
end end
# Print the tokens that the lexer generates from a source script. # Print the tokens that the lexer generates from a source script.
def tokens(source) def tokens(script)
puts Lexer.new.tokenize(File.read(source)).inspect puts Lexer.new.tokenize(script).inspect
end end
# Compile a single source file to JavaScript. # Compile a single source file to JavaScript.
def compile(source) def compile(script, source='')
begin begin
CoffeeScript.compile(File.open(source)) CoffeeScript.compile(script)
rescue CoffeeScript::ParseError => e rescue CoffeeScript::ParseError => e
STDERR.puts e.message(source) STDERR.puts e.message(source)
exit(1) unless @options[:watch] exit(1) unless @options[:watch]

View File

@ -26,12 +26,12 @@ prechigh
left '<=' '<' '>' '>=' left '<=' '<' '>' '>='
right '==' '!=' IS AINT right '==' '!=' IS AINT
left '&&' '||' AND OR left '&&' '||' AND OR
right '-=' '+=' '/=' '*=' '||=' '&&=' right '-=' '+=' '/=' '*='
right DELETE right DELETE
left "." left "."
right THROW FOR IN WHILE NEW right THROW FOR IN WHILE NEW
left UNLESS IF ELSE left UNLESS IF ELSE
left ":" left ":" '||:' '&&:'
right RETURN right RETURN
preclow preclow
@ -173,8 +173,8 @@ 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]) }
| 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]) } | DELETE Expression { result = OpNode.new(val[0], val[1]) }
; ;

View File

@ -112,6 +112,7 @@ module CoffeeScript
# Matches and consumes comments. # Matches and consumes comments.
def comment_token def comment_token
return false unless comment = @chunk[COMMENT, 1] return false unless comment = @chunk[COMMENT, 1]
@line += comment.scan(MULTILINER).length
token(:COMMENT, comment.gsub(COMMENT_CLEANER, '').split(MULTILINER)) token(:COMMENT, comment.gsub(COMMENT_CLEANER, '').split(MULTILINER))
token("\n", "\n") token("\n", "\n")
@i += comment.length @i += comment.length

View File

@ -342,7 +342,7 @@ module CoffeeScript
"aint" => "!==", "aint" => "!==",
'not' => '!', 'not' => '!',
} }
CONDITIONALS = ['||=', '&&='] CONDITIONALS = ['||:', '&&:']
attr_reader :operator, :first, :second attr_reader :operator, :first, :second