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,32 +30,34 @@ 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;
} }
td { tr, td {
padding: 2px 12px 2px 0; margin: 0; padding: 0;
} }
td {
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;
border: 1px solid #cacaca; border: 1px solid #cacaca;
@ -67,4 +69,14 @@ div.code {
div.code button { div.code button {
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,181 +42,303 @@
<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 id="punctuation"> <p>
<b class="header">Punctuation Primer</b> <b>Examples:</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending </p>
the line will do just as well. So newlines can matter, but whitespace is
not otherwise significant. Instead of using curly braces (<b>{ }</b>)
to delimit blocks of code, a period (<b>.</b>) marks the end of a
function, if statement, or try/catch.
</p>
<!-- <%# code_for('punctuation') %> -->
<p id="functions"> <pre>
<b class="header">Functions and Invocation</b> coffee-script path/to/script.cs
Let's start with the best part, shall we? Function literals are my coffee-script --watch --lint experimental.cs
absolute favorite thing about CoffeeScript. coffee-script --print app/scripts/*.cs > concatenation.js</pre>
</p>
<%= code_for('functions', 'cube(5)') %>
<p id="objects_arrays"> <h2>Language Reference</h2>
<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>
<b class="header">Assignment</b> <i>
All assignment in CoffeeScript, whether to a variable or to an object This document is structured so that it can be read from top to bottom,
property, uses a colon. Equal signs are only needed for mathy things. if you like. Later sections use ideas and syntax previously introduced.
</p> In all of the following examples, the source CoffeeScript is provided on
<%= code_for('assignment', 'greeting') %> the left, and the direct compilation into JavaScript is on the right.
<p> Familiarity with JavaScript is assumed, although it would certainly
</p> be nice to have a tutorial that builds from the ground up in the future.
</i>
</p>
<p id="lexical_scope"> <p id="punctuation">
<b class="header">Lexical Scoping and Variable Safety</b> <b class="header">Punctuation Primer</b>
The CoffeeScript compiler takes care to make sure that all of your variables You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
are properly defined within lexical scope &mdash; you never need to declare the line will do just as well. All other whitespace is
<i>var</i> yourself. not significant. Instead of using curly braces <tt>{ }</tt>
</p> to delimit a block of code, use a period <tt>.</tt> to mark the end of a
<%= code_for('scope', 'new_num') %> function, if-statement, switch, or try/catch.
<p> </p>
Notice how the variables are declared with <i>var</i> the first time
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
to the second <b>new_num</b>, in the last line.
</p>
<p id="conditionals"> <p id="functions">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b> <b class="header">Functions and Invocation</b>
</p> Let's start with the best part, shall we? Functions are defined
<%= code_for('conditionals') %> by a list of parameters, an arrow, and the function body. The empty
<p> function looks like this: <tt>=>.</tt>
</p> </p>
<%= code_for('functions', 'cube(5)') %>
<p id="expressions"> <p id="assignment">
<b class="header">Everything is an Expression</b> <b class="header">Assignment</b>
You might have noticed how even though we don't add return statements Use a colon <tt>:</tt> to assign, as in
to CoffeScript functions, they nonetheless return their final value. <a href="http://json.org">JSON</a>. Equal signs are only needed for
The CoffeeScript compiler tries to make sure that every little language mathy things.
construct can be used as an expression. </p>
</p> <%= code_for('assignment', 'greeting') %>
<%= code_for('expressions', 'eldest') %>
<p>
When compiling a function definition, CoffeeScript tries to push down
the return statement to each of the potential final lines of the function.
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 id="while"> <p id="objects_and_arrays">
<b class="header">While Loops</b> <b class="header">Objects and Arrays</b>
The only low-level loop that CoffeeScript provides is the while loop. Object and Array literals look very similar to their JavaScript cousins.
</p> When you spread out each assignment on a separate line, the commas are
<%= code_for('while') %> optional. In this way, assigning object properties looks the same as
assigning local variables.
</p>
<%= code_for('objects_and_arrays', 'song.join(",")') %>
<p id="array_comprehensions"> <p id="lexical_scope">
<b class="header">Array Comprehensions</b> <b class="header">Lexical Scoping and Variable Safety</b>
Most of your looping needs should be handled by array comprehensions. The CoffeeScript compiler takes care to make sure that all of your variables
They replace (and compile into) for loops, handling are properly defined within lexical scope &mdash; you never need to declare
<b>each</b>/<b>forEach</b> style loops, as well as <b>select</b>/<b>filter</b>. <i>var</i> yourself.
Unlike for loops, array comprehensions are expressions, and can be returned </p>
and assigned. <%= code_for('scope', 'new_num') %>
</p> <p>
<%= code_for('array_comprehensions') %> 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,
is not redeclared because <b>num</b> is still in scope. As opposed
to the second <b>new_num</b>, in the last line.
</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="slice"> <p id="conditionals">
<b class="header">Array Slice Literals</b> <b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
CoffeeScript includes a literal syntax for extracting slices of arrays. If/else statements can be written without the use of parenthesis and
The first argument is the index of the first element in the slice, and curly brackets. As with functions and other block expressions, conditionals
the second is the index of the last one. are closed with periods. No period is necessary when using the single-line
</p> postfix form, with the <tt>if</tt> at the end.
<%= code_for('slices', 'three_to_six') %> </p>
<%= code_for('conditionals') %>
<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 id="inheritance"> <p id="expressions">
<b class="header">Inheritance, and Calling Super from a Subclass</b> <b class="header">Everything is an Expression (at least, as much as possible)</b>
JavaScript's prototypal inheritance has always been a bit of a You might have noticed how even though we don't add return statements
brain-bender, with a whole family tree of libraries (Base2, Prototype to CoffeScript functions, they nonetheless return their final value.
). The CoffeeScript compiler tries to make sure that all statements in the
</p> language can be used as expressions. Watch how the <tt>return</tt> gets
<%= code_for('super', true) %> pushed down into each possible branch of execution, in the function
below.
</p>
<%= code_for('expressions', 'eldest') %>
<p>
The same mechanism is used to push down assignment statements, switch
statements, and if-elses (although the ternary operator is preferred).
</p>
<p id="embedded"> <p id="while">
<b class="header">Embedded JavaScript</b> <b class="header">While Loops</b>
If you ever need to interpolate literal JavaScript snippets, you can The only low-level loop that CoffeeScript provides is the while loop.
use backticks to pass JavaScript straight through. </p>
</p> <%= code_for('while') %>
<%= code_for('embedded', true) %> <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="switch"> <p id="array_comprehensions">
<b class="header">Switch/Case/Else</b> <b class="header">Array Comprehensions</b>
Switch statements in JavaScript are fundamentally broken. You can only For your looping needs, CoffeeScript provides array comprehensions
do string comparisons, and need to break at the end of each case similar to Python's. They replace (and compile into) <b>for</b> loops, with
statment to prevent falling through to the default case. CoffeeScript optional guard clauses and the value of the current array index.
compiles switch statements into if-else chains, allowing you to Unlike for loops, array comprehensions are expressions, and can be returned
compare any object (via <b>===</b>), preventing fall-through, and resulting and assigned. They should be able to handle most places where you otherwise
in a returnable expression. would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
</p> </p>
<%= code_for('switch') %> <%= code_for('array_comprehensions') %>
<p id="try"> <p id="slice">
<b class="header">Try/Catch/Finally</b> <b class="header">Array Slice Literals</b>
Try/catch statements just about the same as JavaScript (although CoffeeScript includes syntax for extracting slices of arrays.
they work as expressions). No braces required. The first argument is the index of the first element in the slice, and
</p> the second is the index of the last one.
<%= code_for('try') %> </p>
<%= code_for('slices', 'three_to_six') %>
<p id="try"> <p id="super">
<b class="header">Multiline Strings</b> <b class="header">Calling Super from a Subclass</b>
Multiline strings are allowed in CoffeeScript. JavaScript's prototypal inheritance has always been a bit of a
</p> brain-bender, with a whole family tree of libraries that provide a cleaner
<%= code_for('strings') %> 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>
<%= code_for('super', true) %>
</div> <p id="embedded">
<b class="header">Embedded JavaScript</b>
If you ever need to interpolate literal JavaScript snippets, you can
use backticks to pass JavaScript straight through.
</p>
<%= 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">
<b class="header">Switch/Case/Else</b>
Switch statements in JavaScript are fundamentally broken. You can only
do string comparisons, and need to break at the end of each case
statment to prevent falling through to the default case. CoffeeScript
compiles switch statements into if-else chains, allowing you to
compare any object (via <b>===</b>), preventing fall-through, and resulting
in a returnable expression.
</p>
<%= code_for('switch') %>
<p id="try">
<b class="header">Try/Catch/Finally</b>
Try/catch statements just about the same as JavaScript (although
they work as expressions). No braces required.
</p>
<%= code_for('try') %>
<p id="try">
<b class="header">Multiline Strings</b>
Multiline strings are allowed in CoffeeScript.
</p>
<%= code_for('strings') %>
</div> </div>

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,61 +28,230 @@
<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 id="punctuation"> <p>
<b class="header">Punctuation Primer</b> <b>Examples:</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending </p>
the line will do just as well. So newlines can matter, but whitespace is
not otherwise significant. Instead of using curly braces (<b>{ }</b>)
to delimit blocks of code, a period (<b>.</b>) marks the end of a
function, if statement, or try/catch.
</p>
<!-- -->
<p id="functions"> <pre>
<b class="header">Functions and Invocation</b> coffee-script path/to/script.cs
Let's start with the best part, shall we? Function literals are my coffee-script --watch --lint experimental.cs
absolute favorite thing about CoffeeScript. coffee-script --print app/scripts/*.cs > concatenation.js</pre>
</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. <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">
<b class="header">Punctuation Primer</b>
You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
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
function, if-statement, switch, or try/catch.
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Let's start with the best part, shall we? 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.
<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.
</pre><pre class="idle"><span class="Storage">var</span> <span class="FunctionName">square</span> = <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) { </pre><pre class="idle"><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="Keyword">return</span> x <span class="Keyword">*</span> x;
@ -98,12 +267,28 @@ 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">Objects and Arrays</b> <b class="header">Assignment</b>
Object and Array literals look very similar. When you spread out Use a colon <tt>:</tt> to assign, as in
each assignment on a separate line, the commas are optional. <a href="http://json.org">JSON</a>. Equal signs are only needed for
</p> mathy things.
<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>] </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>
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>
<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> {
max<span class="Keyword">:</span> <span class="Number">10</span> max<span class="Keyword">:</span> <span class="Number">10</span>
ida<span class="Keyword">:</span> <span class="Number">9</span> ida<span class="Keyword">:</span> <span class="Number">9</span>
@ -122,31 +307,14 @@ 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"> <p id="lexical_scope">
<b class="header">Assignment</b> <b class="header">Lexical Scoping and Variable Safety</b>
All assignment in CoffeeScript, whether to a variable or to an object The CoffeeScript compiler takes care to make sure that all of your variables
property, uses a colon. Equal signs are only needed for mathy things. are properly defined within lexical scope &mdash; you never need to declare
</p> <i>var</i> yourself.
<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> </p>
difficulty<span class="Keyword">:</span> <span class="Number">0.5</span> <div class='code'><pre class="idle">num<span class="Keyword">:</span> <span class="Number">1</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">
<b class="header">Lexical Scoping and Variable Safety</b>
The CoffeeScript compiler takes care to make sure that all of your variables
are properly defined within lexical scope &mdash; you never need to declare
<i>var</i> yourself.
</p>
<div class='code'><pre class="idle">num<span class="Keyword">:</span> <span class="Number">1</span>
<span class="FunctionName">change_numbers</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> <span class="FunctionName">change_numbers</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span>
num<span class="Keyword">:</span> <span class="Number">2</span> num<span class="Keyword">:</span> <span class="Number">2</span>
new_num<span class="Keyword">:</span> <span class="Number">3</span>. new_num<span class="Keyword">:</span> <span class="Number">3</span>.
@ -166,17 +334,28 @@ 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>
</p> If/else statements can be written without the use of parenthesis and
<div class='code'><pre class="idle">mood<span class="Keyword">:</span> greatly_improved <span class="Keyword">if</span> singing 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>
<div class='code'><pre class="idle">mood<span class="Keyword">:</span> greatly_improved <span class="Keyword">if</span> singing
<span class="Keyword">if</span> happy <span class="Keyword">and</span> knows_it <span class="Keyword">if</span> happy <span class="Keyword">and</span> knows_it
claps_hands() claps_hands()
@ -196,17 +375,23 @@ expensive <span class="Keyword">||</span><span class="Keyword">=</span> do_the_m
<span class="Storage">var</span> date <span class="Keyword">=</span> friday ? sue : jill; <span class="Storage">var</span> date <span class="Keyword">=</span> friday ? sue : jill;
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>
</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 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
</p> pushed down into each possible branch of execution, in the function
<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> below.
</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>
<span class="Keyword">if</span> student.excellent_work <span class="Keyword">if</span> student.excellent_work
<span class="String"><span class="String">&quot;</span>A+<span class="String">&quot;</span></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
@ -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,30 +414,23 @@ 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";
} }
}; };
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 </p>
are compiled into ternary operators when possible, so that they can be used
as expressions.
</p>
<p id="while"> <p id="while">
<b class="header">While Loops</b> <b class="header">While Loops</b>
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>
<div class='code'><pre class="idle"><span class="Keyword">while</span> demand <span class="Keyword">&gt;</span> supply <div class='code'><pre class="idle"><span class="Keyword">while</span> demand <span class="Keyword">&gt;</span> supply
sell() sell()
restock(). restock().
@ -269,16 +443,23 @@ 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
</p> would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span> </p>
<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>].
<span class="Comment"><span class="Comment">#</span> Zebra-stripe a table.</span> <span class="Comment"><span class="Comment">#</span> Zebra-stripe a table.</span>
@ -302,13 +483,13 @@ lunch <span class="Keyword">=</span> d;
} }
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
<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>
<div class='code'><pre class="idle">nums<span class="Keyword">:</span> [<span class="Number">0</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="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>] <div class='code'><pre class="idle">nums<span class="Keyword">:</span> [<span class="Number">0</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="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]
three_to_six<span class="Keyword">:</span> nums[<span class="Number">3</span>, <span class="Number">6</span>] three_to_six<span class="Keyword">:</span> nums[<span class="Number">3</span>, <span class="Number">6</span>]
</pre><pre class="idle"><span class="Storage">var</span> nums <span class="Keyword">=</span> [<span class="Number">0</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="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]; </pre><pre class="idle"><span class="Storage">var</span> nums <span class="Keyword">=</span> [<span class="Number">0</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="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>];
<span class="Storage">var</span> three_to_six <span class="Keyword">=</span> nums.<span class="LibraryFunction">slice</span>(<span class="Number">3</span>, <span class="Number">6</span> <span class="Keyword">+</span> <span class="Number">1</span>); <span class="Storage">var</span> three_to_six <span class="Keyword">=</span> nums.<span class="LibraryFunction">slice</span>(<span class="Number">3</span>, <span class="Number">6</span> <span class="Keyword">+</span> <span class="Number">1</span>);
@ -316,13 +497,16 @@ 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:
</p> <a href="http://code.google.com/p/base2/">Base2</a>,
<div class='code'><pre class="idle"><span class="FunctionName">Animal</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> . <a href="http://prototypejs.org/">Prototype.js</a>,
<a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc.
</p>
<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>
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>). 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>).
@ -395,12 +579,12 @@ sam.move();
tom.move(); tom.move();
;'>run</button><br class='clear' /></div> ;'>run</button><br class='clear' /></div>
<p id="embedded"> <p id="embedded">
<b class="header">Embedded JavaScript</b> <b class="header">Embedded JavaScript</b>
If you ever need to interpolate literal JavaScript snippets, you can If you ever need to interpolate literal JavaScript snippets, you can
use backticks to pass JavaScript straight through. use backticks to pass JavaScript straight through.
</p> </p>
<div class='code'><pre class="idle"><span class="FunctionName">js</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> <span class="String"><span class="String">`</span>alert(&quot;Hello JavaScript&quot;);<span class="String">`</span></span>. <div class='code'><pre class="idle"><span class="FunctionName">js</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> <span class="String"><span class="String">`</span>alert(&quot;Hello JavaScript&quot;);<span class="String">`</span></span>.
js() <span class="Keyword">if</span> <span class="Number">10</span> <span class="Keyword">&gt;</span> <span class="Number">9</span> js() <span class="Keyword">if</span> <span class="Number">10</span> <span class="Keyword">&gt;</span> <span class="Number">9</span>
</pre><pre class="idle"><span class="Storage">var</span> <span class="FunctionName">js</span> = <span class="Storage">function</span>() { </pre><pre class="idle"><span class="Storage">var</span> <span class="FunctionName">js</span> = <span class="Storage">function</span>() {
@ -417,16 +601,32 @@ if (10 > 9) {
} }
;'>run</button><br class='clear' /></div> ;'>run</button><br class='clear' /></div>
<p id="switch"> <p id="aliases">
<b class="header">Switch/Case/Else</b> <b class="header">Aliases</b>
Switch statements in JavaScript are fundamentally broken. You can only Because the <tt>==</tt> operator frequently causes undesirable coercion,
do string comparisons, and need to break at the end of each case is intransitive, and has a different meaning than in other languages,
statment to prevent falling through to the default case. CoffeeScript CoffeeScript compiles <tt>==</tt> into <tt>===</tt>, and <tt>!=</tt> into
compiles switch statements into if-else chains, allowing you to <tt>!==</tt>.
compare any object (via <b>===</b>), preventing fall-through, and resulting </p>
in a returnable expression. <p>
</p> <tt>is</tt> also compiles into <tt>===</tt>,
<div class='code'><pre class="idle"><span class="Keyword">switch</span> day and <tt>aint</tt> into <tt>!==</tt>.
</p>
<p>
</p>
<!-- -->
<p id="switch">
<b class="header">Switch/Case/Else</b>
Switch statements in JavaScript are fundamentally broken. You can only
do string comparisons, and need to break at the end of each case
statment to prevent falling through to the default case. CoffeeScript
compiles switch statements into if-else chains, allowing you to
compare any object (via <b>===</b>), preventing fall-through, and resulting
in a returnable expression.
</p>
<div class='code'><pre class="idle"><span class="Keyword">switch</span> day
<span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Tuesday<span class="String">&quot;</span></span> <span class="Keyword">then</span> eat_breakfast() <span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Tuesday<span class="String">&quot;</span></span> <span class="Keyword">then</span> eat_breakfast()
<span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Wednesday<span class="String">&quot;</span></span> <span class="Keyword">then</span> go_to_the_park() <span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Wednesday<span class="String">&quot;</span></span> <span class="Keyword">then</span> go_to_the_park()
<span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Saturday<span class="String">&quot;</span></span> <span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span>Saturday<span class="String">&quot;</span></span>
@ -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> {
@ -448,16 +646,16 @@ if (10 > 9) {
} }
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
<p id="try"> <p id="try">
<b class="header">Try/Catch/Finally</b> <b class="header">Try/Catch/Finally</b>
Try/catch statements just about the same as JavaScript (although Try/catch statements just about the same as JavaScript (although
they work as expressions). No braces required. they work as expressions). No braces required.
</p> </p>
<div class='code'><pre class="idle"><span class="Keyword">try</span> <div class='code'><pre class="idle"><span class="Keyword">try</span>
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> {
@ -470,11 +668,11 @@ if (10 > 9) {
} }
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
<p id="try"> <p id="try">
<b class="header">Multiline Strings</b> <b class="header">Multiline Strings</b>
Multiline strings are allowed in CoffeeScript. Multiline strings are allowed in CoffeeScript.
</p> </p>
<div class='code'><pre class="idle">moby_dick<span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Call me Ishmael. Some years ago --</span> <div class='code'><pre class="idle">moby_dick<span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Call me Ishmael. Some years ago --</span>
<span class="String">never mind how long precisely -- having little</span> <span class="String">never mind how long precisely -- having little</span>
<span class="String">or no money in my purse, and nothing particular</span> <span class="String">or no money in my purse, and nothing particular</span>
<span class="String">to interest me on shore, I thought I would sail</span> <span class="String">to interest me on shore, I thought I would sail</span>
@ -488,8 +686,6 @@ if (10 > 9) {
<span class="String">world...<span class="String">&quot;</span></span>; <span class="String">world...<span class="String">&quot;</span></span>;
</pre><br class='clear' /></div> </pre><br class='clear' /></div>
</div>
</div> </div>
</body> </body>

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