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.
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()
cats_and_dogs_living_together()
catch error
print( error )
print(error)
finally
clean_up().

View File

@ -30,32 +30,34 @@ b.header {
margin: 40px 0 5px 0;
font-size: 16px;
}
table, tr, td {
margin: 0; padding: 0;
table {
margin: 16px 0 0 13px; padding: 0;
width: 625px;
}
td {
padding: 2px 12px 2px 0;
tr, td {
margin: 0; padding: 0;
}
td {
padding: 9px 15px 9px 0;
}
code, pre, tt {
font-family: Monaco, Consolas, "Lucida Console", monospace;
font-size: 12px;
line-height: 18px;
color: #555529;
color: #191955;
}
code {
margin-left: 20px;
tt {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 85%;
padding: 0px 0.2em;
}
pre {
border-left: 6px solid #222255;
margin-left: 13px;
padding: 3px 0 3px 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 {
position: relative;
border: 1px solid #cacaca;
@ -67,4 +69,14 @@ div.code {
div.code button {
position: absolute;
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'
def code_for(file, executable=false)
@stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/
return '' unless File.exists?("documentation/js/#{file}.js")
cs = File.read("documentation/cs/#{file}.cs")
js = File.read("documentation/js/#{file}.js").gsub(@stripper, '')
cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false)
@ -30,10 +31,10 @@
<p>
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
bonus goodies, statements in CoffeeScript correspond one-to-one with their
JavaScript equivalent, it's just another way of saying it.
bonus goodies, statements in CoffeeScript correspond one-to-one with their
equivalent in JavaScript, it's just another way of saying it.
</p>
<!-- <%# code_for('intro') %>-->
@ -41,181 +42,303 @@
<p>
<b>Disclaimer:</b>
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
compiles into pretty-printed JavaScript (the good parts) that can pass through
<a href="http://www.jslint.com/">JSLint</a> warning-free.
explicit or implied, of its suitability for any purpose.</i> That said,
it compiles into clean JavaScript (the good parts) that can use existing
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>
<h2>Table of Contents</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.
</i>
</p>
<p>
<a href="#overview">Mini Overview</a><br />
<a href="#installation">Installation and Usage</a><br />
<a href="#punctuation">Punctuation Primer</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="#objects_and_arrays">Objects and Arrays</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="#expressions">Everything is an Expression</a><br />
<a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</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="#aliases">Aliases</a><br />
<a href="#switch">Switch/Case/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br />
</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>
In all of the following examples, the source CoffeeScript is provided on
the left, and the direct compilation into JavaScript is on the right.
Installing the gem provides the <tt>coffee-script</tt> command, which can
be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug. 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>
<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">
<b class="header">Punctuation Primer</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending
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>
<b>Examples:</b>
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Let's start with the best part, shall we? Function literals are my
absolute favorite thing about CoffeeScript.
</p>
<%= code_for('functions', 'cube(5)') %>
<pre>
coffee-script path/to/script.cs
coffee-script --watch --lint experimental.cs
coffee-script --print app/scripts/*.cs > concatenation.js</pre>
<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>
<h2>Language Reference</h2>
<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>
<%= code_for('assignment', 'greeting') %>
<p>
</p>
<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="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>
<%= code_for('scope', 'new_num') %>
<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="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="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
</p>
<%= code_for('conditionals') %>
<p>
</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>
<%= code_for('functions', 'cube(5)') %>
<p id="expressions">
<b class="header">Everything is an Expression</b>
You might have noticed how even though we don't add return statements
to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that every little language
construct can be used as an expression.
</p>
<%= 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="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>
<%= code_for('assignment', 'greeting') %>
<p id="while">
<b class="header">While Loops</b>
The only low-level loop that CoffeeScript provides is the while loop.
</p>
<%= code_for('while') %>
<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>
<%= code_for('objects_and_arrays', 'song.join(",")') %>
<p id="array_comprehensions">
<b class="header">Array Comprehensions</b>
Most of your looping needs should be handled by array comprehensions.
They replace (and compile into) for loops, handling
<b>each</b>/<b>forEach</b> style loops, as well as <b>select</b>/<b>filter</b>.
Unlike for loops, array comprehensions are expressions, and can be returned
and assigned.
</p>
<%= code_for('array_comprehensions') %>
<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>
<%= code_for('scope', 'new_num') %>
<p>
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">
<b class="header">Array Slice Literals</b>
CoffeeScript includes a literal syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and
the second is the index of the last one.
</p>
<%= code_for('slices', 'three_to_six') %>
<p id="conditionals">
<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>
<%= 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">
<b class="header">Inheritance, and Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a
brain-bender, with a whole family tree of libraries (Base2, Prototype
).
</p>
<%= code_for('super', true) %>
<p id="expressions">
<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
to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that all statements in the
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>
<%= 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">
<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="while">
<b class="header">While Loops</b>
The only low-level loop that CoffeeScript provides is the while loop.
</p>
<%= 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="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="array_comprehensions">
<b class="header">Array Comprehensions</b>
For your looping needs, CoffeeScript provides array comprehensions
similar to Python's. They replace (and compile into) <b>for</b> loops, with
optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned
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>
<%= code_for('array_comprehensions') %>
<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="slice">
<b class="header">Array Slice Literals</b>
CoffeeScript includes syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and
the second is the index of the last one.
</p>
<%= code_for('slices', 'three_to_six') %>
<p id="try">
<b class="header">Multiline Strings</b>
Multiline strings are allowed in CoffeeScript.
</p>
<%= code_for('strings') %>
<p id="super">
<b class="header">Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a
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>
<%= 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>

View File

@ -3,11 +3,7 @@
if (student.excellent_work) {
return "A+";
} else if (student.okay_stuff) {
return if (student.tried_hard) {
return "B";
} else {
return "B-";
};
return student.tried_hard ? "B" : "B-";
} else {
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") {
go_to_the_park();
} else if (day === "Saturday") {
if (day === bingo_day) {
go_to_bingo();
};
day === bingo_day ? go_to_bingo() : null;
} else if (day === "Sunday") {
go_to_church();
} else {

View File

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

View File

@ -17,10 +17,10 @@
<p>
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
bonus goodies, statements in CoffeeScript correspond one-to-one with their
JavaScript equivalent, it's just another way of saying it.
bonus goodies, statements in CoffeeScript correspond one-to-one with their
equivalent in JavaScript, it's just another way of saying it.
</p>
<!-- -->
@ -28,61 +28,230 @@
<p>
<b>Disclaimer:</b>
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
compiles into pretty-printed JavaScript (the good parts) that can pass through
<a href="http://www.jslint.com/">JSLint</a> warning-free.
explicit or implied, of its suitability for any purpose.</i> That said,
it compiles into clean JavaScript (the good parts) that can use existing
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>
<h2>Table of Contents</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.
</i>
</p>
<p>
<a href="#overview">Mini Overview</a><br />
<a href="#installation">Installation and Usage</a><br />
<a href="#punctuation">Punctuation Primer</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="#objects_and_arrays">Objects and Arrays</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="#expressions">Everything is an Expression</a><br />
<a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</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="#aliases">Aliases</a><br />
<a href="#switch">Switch/Case/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br />
</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>
In all of the following examples, the source CoffeeScript is provided on
the left, and the direct compilation into JavaScript is on the right.
Installing the gem provides the <tt>coffee-script</tt> command, which can
be used to compile CoffeeScript <tt>.cs</tt> files into JavaScript, as
well as debug. 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>
<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">
<b class="header">Punctuation Primer</b>
You don't need to use semicolons to (<b>;</b>) terminate expressions, ending
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>
<b>Examples:</b>
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Let's start with the best part, shall we? Function literals are my
absolute favorite thing about CoffeeScript.
</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.
<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">
<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.
</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;
@ -98,12 +267,28 @@ var cube = function(x) {
};
;alert(cube(5));'>run: cube(5)</button><br class='clear' /></div>
<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>
<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 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>
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> {
max<span class="Keyword">:</span> <span class="Number">10</span>
ida<span class="Keyword">:</span> <span class="Number">9</span>
@ -122,31 +307,14 @@ var ages = {
tim: 11
};
;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">
<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>
<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>
num<span class="Keyword">:</span> <span class="Number">2</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();
;alert(new_num);'>run: new_num</button><br class='clear' /></div>
<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>
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="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
</p>
<div class='code'><pre class="idle">mood<span class="Keyword">:</span> greatly_improved <span class="Keyword">if</span> singing
<p id="conditionals">
<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>
<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
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;
expensive <span class="Keyword">=</span> expensive <span class="Keyword">||</span> do_the_math();
</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">
<b class="header">Everything is an Expression</b>
You might have noticed how even though we don't add return statements
to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that every little language
construct can be used as an expression.
</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>
<p id="expressions">
<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
to CoffeScript functions, they nonetheless return their final value.
The CoffeeScript compiler tries to make sure that all statements in the
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>
<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="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
@ -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">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">return</span> <span class="Keyword">if</span> (student.tried_hard) {
<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">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">else</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) {
return "A+";
} else if (student.okay_stuff) {
return if (student.tried_hard) {
return "B";
} else {
return "B-";
};
return student.tried_hard ? "B" : "B-";
} else {
return "C";
}
};
var eldest = 24 > 21 ? "Liz" : "Ike";
;alert(eldest);'>run: eldest</button><br class='clear' /></div>
<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>
The same mechanism is used to push down assignment statements, switch
statements, and if-elses (although the ternary operator is preferred).
</p>
<p id="while">
<b class="header">While Loops</b>
The only low-level loop that CoffeeScript provides is the while loop.
</p>
<div class='code'><pre class="idle"><span class="Keyword">while</span> demand <span class="Keyword">&gt;</span> supply
<p id="while">
<b class="header">While Loops</b>
The only low-level loop that CoffeeScript provides is the while loop.
</p>
<div class='code'><pre class="idle"><span class="Keyword">while</span> demand <span class="Keyword">&gt;</span> supply
sell()
restock().
@ -269,16 +443,23 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
buy();
}
</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">
<b class="header">Array Comprehensions</b>
Most of your looping needs should be handled by array comprehensions.
They replace (and compile into) for loops, handling
<b>each</b>/<b>forEach</b> style loops, as well as <b>select</b>/<b>filter</b>.
Unlike for loops, array comprehensions are expressions, and can be returned
and assigned.
</p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
<p id="array_comprehensions">
<b class="header">Array Comprehensions</b>
For your looping needs, CoffeeScript provides array comprehensions
similar to Python's. They replace (and compile into) <b>for</b> loops, with
optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned
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>
<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>].
<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>
<p id="slice">
<b class="header">Array Slice Literals</b>
CoffeeScript includes a literal syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and
the second is the index of the last one.
</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>]
<p id="slice">
<b class="header">Array Slice Literals</b>
CoffeeScript includes syntax for extracting slices of arrays.
The first argument is the index of the first element in the slice, and
the second is the index of the last one.
</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>]
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>];
<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);
;alert(three_to_six);'>run: three_to_six</button><br class='clear' /></div>
<p id="inheritance">
<b class="header">Inheritance, and Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a
brain-bender, with a whole family tree of libraries (Base2, Prototype
).
</p>
<div class='code'><pre class="idle"><span class="FunctionName">Animal</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span> .
<p id="super">
<b class="header">Calling Super from a Subclass</b>
JavaScript's prototypal inheritance has always been a bit of a
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>
<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>
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();
;'>run</button><br class='clear' /></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>
<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>.
<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>
<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>
</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>
<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
<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">
<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>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>
@ -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>) {
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">if</span> (day <span class="Keyword">===</span> bingo_day) {
go_to_bingo();
};
day <span class="Keyword">===</span> bingo_day ? go_to_bingo() : <span class="BuiltInConstant">null</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();
} <span class="Keyword">else</span> {
@ -448,16 +646,16 @@ if (10 > 9) {
}
</pre><br class='clear' /></div>
<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>
<div class='code'><pre class="idle"><span class="Keyword">try</span>
<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>
<div class='code'><pre class="idle"><span class="Keyword">try</span>
all_hell_breaks_loose()
cats_and_dogs_living_together()
<span class="Keyword">catch</span> error
print( error )
print(error)
<span class="Keyword">finally</span>
clean_up().
</pre><pre class="idle"><span class="Keyword">try</span> {
@ -470,11 +668,11 @@ if (10 > 9) {
}
</pre><br class='clear' /></div>
<p id="try">
<b class="header">Multiline Strings</b>
Multiline strings are allowed in CoffeeScript.
</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>
<p id="try">
<b class="header">Multiline Strings</b>
Multiline strings are allowed in CoffeeScript.
</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>
<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">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>;
</pre><br class='clear' /></div>
</div>
</div>
</body>

View File

@ -41,12 +41,13 @@ Usage:
# Compiles (or partially compiles) the source CoffeeScript file, returning
# the desired JS, tokens, or lint results.
def compile_javascript(source)
return tokens(source) if @options[:tokens]
contents = compile(source)
return unless contents
return puts(contents) if @options[:print]
return lint(contents) if @options[:lint]
File.open(path_for(source), 'w+') {|f| f.write(contents) }
script = File.read(source)
return tokens(script) if @options[:tokens]
js = compile(script, source)
return unless js
return puts(js) if @options[:print]
return lint(js) if @options[:lint]
File.open(path_for(source), 'w+') {|f| f.write(js) }
end
# 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.
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
# Print the tokens that the lexer generates from a source script.
def tokens(source)
puts Lexer.new.tokenize(File.read(source)).inspect
def tokens(script)
puts Lexer.new.tokenize(script).inspect
end
# Compile a single source file to JavaScript.
def compile(source)
def compile(script, source='')
begin
CoffeeScript.compile(File.open(source))
CoffeeScript.compile(script)
rescue CoffeeScript::ParseError => e
STDERR.puts e.message(source)
exit(1) unless @options[:watch]

View File

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

View File

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

View File

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