Compare commits

...

9 Commits
0.5.1 ... 0.5.2

55 changed files with 457 additions and 382 deletions

View File

@@ -38,6 +38,14 @@ task 'build:underscore', 'rebuild the Underscore.coffee documentation page', ->
exec 'uv -s coffeescript -t idle -h examples/underscore.coffee > documentation/underscore.html'
task 'build:browser', 'rebuild the merged script for inclusion in the browser', ->
exec 'rake browser'
task 'doc', 'watch and continually rebuild the documentation', ->
exec 'rake doc'
task 'test', 'run the CoffeeScript language test suite', ->
process.mixin require 'assert'
test_count: 0

View File

@@ -1,6 +1,8 @@
require 'erb'
require 'fileutils'
require 'rake/testtask'
require 'rubygems'
require 'yui/compressor'
desc "Build the documentation page"
task :doc do
@@ -18,3 +20,12 @@ task :doc do
sleep 1
end
end
desc "Build the single concatenated and minified script for the browser"
task :browser do
sources = %w(rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js)
code = sources.map {|s| File.read('lib/' + s) }.join('')
code = YUI::JavaScriptCompressor.new.compress(code)
File.open('extras/coffee-script.js', 'w+') {|f| f.write(code) }
end

View File

@@ -1,7 +1,7 @@
<%
require 'uv'
def code_for(file, executable=false)
@stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/
@stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\n*\Z|^ )/
return '' unless File.exists?("documentation/js/#{file}.js")
cs = File.read("documentation/coffee/#{file}.coffee")
js = File.read("documentation/js/#{file}.js").gsub(@stripper, '')
@@ -60,6 +60,7 @@
<a href="#comparisons">Chained Comparisons</a>
<a href="#strings">Multiline Strings and Heredocs</a>
<a href="#cake">Cake, and Cakefiles</a>
<a href="#scripts">"text/coffeescript" Script Tags</a>
<a href="#resources">Resources</a>
<a href="#change_log">Change Log</a>
</div>
@@ -107,7 +108,7 @@ alert reverse '!tpircseeffoC'</textarea>
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.5.1">0.5.1</a>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>
</p>
<h2>
@@ -138,7 +139,7 @@ alert reverse '!tpircseeffoC'</textarea>
</h2>
<p>
The CoffeeScript compiler is written in pure CoffeeScript, using a
The CoffeeScript compiler is written in pure CoffeeScript, using a
<a href="http://github.com/jashkenas/coffee-script/blob/master/src/grammar.coffee">small DSL</a>
on top of the <a href="http://github.com/zaach/jison">Jison parser generator</a>, and is available
as a <a href="http://nodejs.org/">Node.js</a> utility. The core compiler however,
@@ -152,7 +153,7 @@ alert reverse '!tpircseeffoC'</textarea>
<a href="http://nodejs.org/">Node.js</a>, 0.1.30 or higher. Then clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download the latest
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.5.1">0.5.1</a>.
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
@@ -214,6 +215,14 @@ sudo bin/cake install</pre>
conjunction with <tt>--watch</tt>)
</td>
</tr>
<tr>
<td><code>-s, --stdio</code></td>
<td>
Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT.
Good for use with processes written in other languages. An example:<br />
<tt>cat src/cake.coffee | coffee -s</tt>
</td>
</tr>
<tr>
<td><code>-e, --eval</code></td>
<td>
@@ -717,6 +726,34 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('cake_tasks') %>
<h2>
<span id="scripts" class="bookmark"></span>
"text/coffeescript" Script Tags
</h2>
<p>
While it's not recommended for serious use, CoffeeScripts may be included
directly within the browser using <tt>&lt;script type="text/coffeescript"&gt;</tt>
tags. The codebase includes a compressed and minified version of the compiler
(<a href="extras/coffee-script.js">Download current version here, 43k when gzipped</a>).
Include <tt>coffee-script.js</tt> on the page <b>after</b> any <tt>text/coffeescript</tt> tags
with inline CoffeeScript, and it will compile and evaluate them in order.
</p>
<p>
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
as well as jQuery for the menu, is implemented in just this way.
View source and look at the bottom of the page to see the example.
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
so you can pop open Firebug and try compiling some strings.
</p>
<p>
The usual caveats about CoffeeScript apply &mdash; your inline scripts will
run within a closure wrapper, so if you want to expose global variables or
functions, attach them to the <tt>window</tt> object.
</p>
<h2>
<span id="resources" class="bookmark"></span>
Resources
@@ -745,6 +782,15 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
Change Log
</h2>
<p>
<b class="header" style="margin-top: 20px;">0.5.2</b>
Added a compressed version of the compiler for inclusion in web pages as
<br /><tt>extras/coffee-script.js</tt>. It'll automatically run any script tags
with type <tt>text/coffeescript</tt> for you. Added a <tt>--stdio</tt> option
to the <tt>coffee</tt> command, for piped-in compiles.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.1</b>
Improvements to null soaking with the existential operator, including
@@ -915,53 +961,42 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</div>
<script type="text/javascript" src="lib/rewriter.js"></script>
<script type="text/javascript" src="lib/lexer.js"></script>
<script type="text/javascript" src="lib/parser.js"></script>
<script type="text/javascript" src="lib/scope.js"></script>
<script type="text/javascript" src="lib/nodes.js"></script>
<script type="text/javascript" src="lib/coffee-script.js"></script>
<script type="text/coffeescript">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
window.repl_compile: ->
source: $('#repl_source').val()
window.compiled_js: ''
try
window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
catch error then alert error
$('#repl_results').html window.compiled_js
<script type="text/javascript">
window.repl_compile = function() {
var source = $('#repl_source').val();
window.compiled_js = '';
try {
window.compiled_js = CoffeeScript.compile(source, {no_wrap: true});
} catch(error) {
alert(error);
}
$('#repl_results').html(window.compiled_js);
};
window.repl_run = function() {
try {
eval(window.compiled_js);
} catch(error) {
alert(error);
}
};
window.repl_run: ->
try
eval window.compiled_js
catch error then alert error
nav: $('.navigation')
current_nav: null
close_menus: ->
current_nav.removeClass 'active' if current_nav
current_nav: null
nav.click (e) ->
return if e.target.tagName.toLowerCase() is 'a'
if this isnt (current_nav and current_nav[0])
close_menus();
current_nav: $(this)
current_nav.addClass 'active'
false
$(document.body).click -> close_menus()
var nav = $('.navigation');
var currentNav = null;
var closeMenus = function() {
if (currentNav) currentNav.removeClass('active');
currentNav = null;
};
nav.click(function(e) {
if (e.target.tagName.toLowerCase() == 'a') return;
if (this !== (currentNav && currentNav[0])) {
closeMenus();
currentNav = $(this);
currentNav.addClass('active');
}
return false;
});
$(document.body).click(function() {
closeMenus();
});
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="extras/coffee-script.js"></script>
</body>
</html>

View File

@@ -11,4 +11,4 @@
}
car.speed < speed_limit ? accelerate() : null;
print("My name is " + this.name);
})();
})();

View File

@@ -5,4 +5,4 @@
return alert(arguments.reverse());
};
backwards("stairway", "to", "heaven");
})();
})();

View File

@@ -23,4 +23,4 @@
}
}
}
})();
})();

View File

@@ -2,4 +2,4 @@
var difficulty, greeting;
greeting = "Hello CoffeeScript";
difficulty = 0.5;
})();
})();

View File

@@ -11,4 +11,4 @@
}
return _a;
});
})();
})();

View File

@@ -2,4 +2,4 @@
var cholesterol, healthy;
cholesterol = 127;
healthy = (200 > cholesterol) && (cholesterol > 60);
})();
})();

View File

@@ -9,4 +9,4 @@
}
date = friday ? sue : jill;
expensive = expensive || do_the_math();
})();
})();

View File

@@ -3,4 +3,4 @@
hi = function() {
return [document.title, "Hello JavaScript"].join(": ");
};
})();
})();

View File

@@ -4,4 +4,4 @@
solipsism = true;
}
speed = (typeof speed !== "undefined" && speed !== null) ? speed : 140;
})();
})();

View File

@@ -10,4 +10,4 @@
}
};
eldest = 24 > 21 ? "Liz" : "Ike";
})();
})();

View File

@@ -1,4 +1,4 @@
(function(){
var one, six, three, two;
six = ((one = 1)) + ((two = 2)) + ((three = 3));
})();
})();

View File

@@ -9,4 +9,4 @@
}}
return _a;
}).call(this).slice(0, 10);
})();
})();

View File

@@ -6,4 +6,4 @@
return "And the error is ... " + error;
}
}).call(this));
})();
})();

View File

@@ -12,4 +12,4 @@
});
})(this));
};
})();
})();

View File

@@ -6,4 +6,4 @@
cube = function cube(x) {
return square(x) * x;
};
})();
})();

View File

@@ -1,4 +1,4 @@
(function(){
var html;
html = "<strong>\n cup of coffeescript\n</strong>";
})();
})();

View File

@@ -8,4 +8,4 @@
city = _a[0];
temp = _a[1];
forecast = _a[2];
})();
})();

View File

@@ -14,4 +14,4 @@
}}
return _a;
}).call(this);
})();
})();

View File

@@ -14,4 +14,4 @@
_c = _b.address;
street = _c[0];
city = _c[1];
})();
})();

View File

@@ -7,4 +7,4 @@
tim: 11
};
matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
})();
})();

View File

@@ -40,4 +40,4 @@
}
return _a;
}).call(this);
})();
})();

View File

@@ -5,4 +5,4 @@
_a = [and_switch, bait];
bait = _a[0];
and_switch = _a[1];
})();
})();

View File

@@ -18,4 +18,4 @@
}
return _f;
};
})();
})();

View File

@@ -7,4 +7,4 @@
return num = 10;
};
new_num = change_numbers();
})();
})();

View File

@@ -3,4 +3,4 @@
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
three_to_six = numbers.slice(3, 6 + 1);
numbers_copy = numbers.slice(0, numbers.length);
})();
})();

View File

@@ -1,4 +1,4 @@
(function(){
var _a;
(_a = lottery.draw_winner()) == undefined ? undefined : _a.address == undefined ? undefined : _a.address.zipcode;
})();
})();

View File

@@ -13,4 +13,4 @@
alert("Gold: " + gold);
alert("Silver: " + silver);
alert("The Field: " + the_field);
})();
})();

View File

@@ -2,4 +2,4 @@
var numbers;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
numbers.splice.apply(numbers, [3, 6 - 3 + 1].concat([-3, -4, -5, -6]));
})();
})();

View File

@@ -6,4 +6,4 @@ or no money in my purse, and nothing particular \
to interest me on shore, I thought I would sail \
about a little and see the watery part of the \
world...";
})();
})();

View File

@@ -34,4 +34,4 @@
tom = new Horse("Tommy the Palomino");
sam.move();
tom.move();
})();
})();

View File

@@ -15,4 +15,4 @@
} else {
go_to_work();
}
})();
})();

View File

@@ -7,4 +7,4 @@
} finally {
clean_up();
}
})();
})();

View File

@@ -19,4 +19,4 @@ One fell out and bumped his head.");
}
return _a;
}).call(this);
})();
})();

View File

@@ -1,4 +1,12 @@
This folder includes rough cuts of CoffeeScript syntax highlighters for
EXTRAS:
"extras/coffee-script.js" is a concatenated and compressed version of the
CoffeeScript compiler. To use it in the browser, include the script after any
inline script tags of type "text/coffeescript" on the page. It will compile
and evaluate all of the scripts in order.
This folder also includes rough cuts of CoffeeScript syntax highlighters for
TextMate and Vim. Improvements to their lexing ability are always welcome.
To install the TextMate bundle, drop it into:

1
extras/coffee-script.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -46,6 +46,7 @@
<a href="#comparisons">Chained Comparisons</a>
<a href="#strings">Multiline Strings and Heredocs</a>
<a href="#cake">Cake, and Cakefiles</a>
<a href="#scripts">"text/coffeescript" Script Tags</a>
<a href="#resources">Resources</a>
<a href="#change_log">Change Log</a>
</div>
@@ -93,7 +94,7 @@ alert reverse '!tpircseeffoC'</textarea>
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.5.1">0.5.1</a>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>
</p>
<h2>
@@ -235,7 +236,7 @@ cubed_list = (function() {
</h2>
<p>
The CoffeeScript compiler is written in pure CoffeeScript, using a
The CoffeeScript compiler is written in pure CoffeeScript, using a
<a href="http://github.com/jashkenas/coffee-script/blob/master/src/grammar.coffee">small DSL</a>
on top of the <a href="http://github.com/zaach/jison">Jison parser generator</a>, and is available
as a <a href="http://nodejs.org/">Node.js</a> utility. The core compiler however,
@@ -249,7 +250,7 @@ cubed_list = (function() {
<a href="http://nodejs.org/">Node.js</a>, 0.1.30 or higher. Then clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download the latest
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.5.1">0.5.1</a>.
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
@@ -311,6 +312,14 @@ sudo bin/cake install</pre>
conjunction with <tt>--watch</tt>)
</td>
</tr>
<tr>
<td><code>-s, --stdio</code></td>
<td>
Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT.
Good for use with processes written in other languages. An example:<br />
<tt>cat src/cake.coffee | coffee -s</tt>
</td>
</tr>
<tr>
<td><code>-e, --eval</code></td>
<td>
@@ -1597,6 +1606,34 @@ task(<span class="String"><span class="String">'</span>test<span class="String">
});
</pre><br class='clear' /></div>
<h2>
<span id="scripts" class="bookmark"></span>
"text/coffeescript" Script Tags
</h2>
<p>
While it's not recommended for serious use, CoffeeScripts may be included
directly within the browser using <tt>&lt;script type="text/coffeescript"&gt;</tt>
tags. The codebase includes a compressed and minified version of the compiler
(<a href="extras/coffee-script.js">Download current version here, 43k when gzipped</a>).
Include <tt>coffee-script.js</tt> on the page <b>after</b> any <tt>text/coffeescript</tt> tags
with inline CoffeeScript, and it will compile and evaluate them in order.
</p>
<p>
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
as well as jQuery for the menu, is implemented in just this way.
View source and look at the bottom of the page to see the example.
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
so you can pop open Firebug and try compiling some strings.
</p>
<p>
The usual caveats about CoffeeScript apply &mdash; your inline scripts will
run within a closure wrapper, so if you want to expose global variables or
functions, attach them to the <tt>window</tt> object.
</p>
<h2>
<span id="resources" class="bookmark"></span>
Resources
@@ -1625,6 +1662,15 @@ task(<span class="String"><span class="String">'</span>test<span class="String">
Change Log
</h2>
<p>
<b class="header" style="margin-top: 20px;">0.5.2</b>
Added a compressed version of the compiler for inclusion in web pages as
<br /><tt>extras/coffee-script.js</tt>. It'll automatically run any script tags
with type <tt>text/coffeescript</tt> for you. Added a <tt>--stdio</tt> option
to the <tt>coffee</tt> command, for piped-in compiles.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.1</b>
Improvements to null soaking with the existential operator, including
@@ -1795,53 +1841,42 @@ task(<span class="String"><span class="String">'</span>test<span class="String">
</div>
<script type="text/javascript" src="lib/rewriter.js"></script>
<script type="text/javascript" src="lib/lexer.js"></script>
<script type="text/javascript" src="lib/parser.js"></script>
<script type="text/javascript" src="lib/scope.js"></script>
<script type="text/javascript" src="lib/nodes.js"></script>
<script type="text/javascript" src="lib/coffee-script.js"></script>
<script type="text/coffeescript">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
window.repl_compile: ->
source: $('#repl_source').val()
window.compiled_js: ''
try
window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
catch error then alert error
$('#repl_results').html window.compiled_js
<script type="text/javascript">
window.repl_compile = function() {
var source = $('#repl_source').val();
window.compiled_js = '';
try {
window.compiled_js = CoffeeScript.compile(source, {no_wrap: true});
} catch(error) {
alert(error);
}
$('#repl_results').html(window.compiled_js);
};
window.repl_run = function() {
try {
eval(window.compiled_js);
} catch(error) {
alert(error);
}
};
window.repl_run: ->
try
eval window.compiled_js
catch error then alert error
nav: $('.navigation')
current_nav: null
close_menus: ->
current_nav.removeClass 'active' if current_nav
current_nav: null
nav.click (e) ->
return if e.target.tagName.toLowerCase() is 'a'
if this isnt (current_nav and current_nav[0])
close_menus();
current_nav: $(this)
current_nav.addClass 'active'
false
$(document.body).click -> close_menus()
var nav = $('.navigation');
var currentNav = null;
var closeMenus = function() {
if (currentNav) currentNav.removeClass('active');
currentNav = null;
};
nav.click(function(e) {
if (e.target.tagName.toLowerCase() == 'a') return;
if (this !== (currentNav && currentNav[0])) {
closeMenus();
currentNav = $(this);
currentNav.addClass('active');
}
return false;
});
$(document.body).click(function() {
closeMenus();
});
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="extras/coffee-script.js"></script>
</body>
</html>

View File

@@ -77,4 +77,4 @@
});
});
};
})();
})();

View File

@@ -1,5 +1,5 @@
(function(){
var lexer, parser, path;
var _a, _b, lexer, parser, path, tag;
// Set up for both the browser and the server.
if ((typeof process !== "undefined" && process !== null)) {
process.mixin(require('nodes'));
@@ -32,7 +32,7 @@
return this.pos;
}
};
exports.VERSION = '0.5.1';
exports.VERSION = '0.5.2';
// Compile CoffeeScript to JavaScript, using the Coffee/Jison compiler.
exports.compile = function compile(code, options) {
return (parser.parse(lexer.tokenize(code))).compile(options);
@@ -45,17 +45,13 @@
exports.tree = function tree(code) {
return parser.parse(lexer.tokenize(code));
};
// Pretty-print a token stream.
exports.print_tokens = function print_tokens(tokens) {
var _a, _b, _c, strings, token;
strings = (function() {
_a = []; _b = tokens;
for (_c = 0; _c < _b.length; _c++) {
token = _b[_c];
_a.push('[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']');
}
return _a;
}).call(this);
return puts(strings.join(' '));
};
})();
// Activate CoffeeScript in the browser by having it compile and eval
// all script tags with a content-type of text/coffeescript.
if ((typeof document !== "undefined" && document !== null) && document.getElementsByTagName) {
_a = document.getElementsByTagName('script');
for (_b = 0; _b < _a.length; _b++) {
tag = _a[_b];
tag.type === 'text/coffeescript' ? eval(exports.compile(tag.innerHTML)) : null;
}
}
})();

View File

@@ -1,11 +1,11 @@
(function(){
var BANNER, SWITCHES, coffee, compile_script, compile_scripts, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, watch_scripts, write_js;
var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js;
fs = require('fs');
path = require('path');
coffee = require('coffee-script');
optparse = require('optparse');
CoffeeScript = require('coffee-script');
BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee";
SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
options = {};
sources = [];
option_parser = null;
@@ -13,14 +13,23 @@
exports.run = function run() {
var flags, separator;
parse_options();
if (options.help) {
return usage();
}
if (options.version) {
return version();
}
if (options.interactive) {
return require('repl');
}
if (options.stdio) {
return compile_stdio();
}
if (options.eval) {
return compile_script('terminal', sources[0]);
return compile_script('unknown', sources[0]);
}
if (!(sources.length)) {
usage();
return usage();
}
separator = sources.indexOf('--');
flags = [];
@@ -42,7 +51,7 @@
};
// The "--version" message.
version = function version() {
puts("CoffeeScript version " + coffee.VERSION);
puts("CoffeeScript version " + CoffeeScript.VERSION);
return process.exit(0);
};
// Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
@@ -64,36 +73,47 @@
// Compile a single source script, containing the given code, according to the
// requested options. Both compile_scripts and watch_scripts share this method.
compile_script = function compile_script(source, code) {
var js, o, opts;
opts = options;
o = opts.no_wrap ? {
no_wrap: true
} : {};
var js, o;
o = options;
try {
if (opts.tokens) {
return coffee.print_tokens(coffee.tokenize(code));
} else if (opts.tree) {
return puts(coffee.tree(code).toString());
if (o.tokens) {
return print_tokens(CoffeeScript.tokenize(code));
} else if (o.tree) {
return puts(CoffeeScript.tree(code).toString());
} else {
js = coffee.compile(code, o);
if (opts.run) {
js = CoffeeScript.compile(code, compile_options());
if (o.run) {
return eval(js);
} else if (opts.lint) {
} else if (o.lint) {
return lint(js);
} else if (opts.print || opts.eval) {
return puts(js);
} else if (o.print || o.eval) {
return print(js);
} else {
return write_js(source, js);
}
}
} catch (err) {
if (opts.watch) {
if (o.watch) {
return puts(err.message);
} else {
throw err;
}
}
};
// Listen for and compile scripts over stdio.
compile_stdio = function compile_stdio() {
var code;
code = '';
process.stdio.open();
process.stdio.addListener('data', function(string) {
if (string) {
return code += string;
}
});
return process.stdio.addListener('close', function() {
return process.stdio.write(CoffeeScript.compile(code, compile_options()));
});
};
// Watch a list of source CoffeeScript files, recompiling them every time the
// files are updated.
watch_scripts = function watch_scripts() {
@@ -143,59 +163,29 @@
jsl.write(js);
return jsl.close();
};
// Pretty-print a token stream.
print_tokens = function print_tokens(tokens) {
var _a, _b, _c, strings, token;
strings = (function() {
_a = []; _b = tokens;
for (_c = 0; _c < _b.length; _c++) {
token = _b[_c];
_a.push('[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']');
}
return _a;
}).call(this);
return puts(strings.join(' '));
};
// Use OptionParser for all the options.
parse_options = function parse_options() {
var oparser, opts, paths;
opts = (options = {});
oparser = (option_parser = new optparse.OptionParser(SWITCHES));
oparser.banner = BANNER;
oparser.add('interactive', function() {
return opts.interactive = true;
});
oparser.add('run', function() {
return opts.run = true;
});
oparser.add('output', function(dir) {
return opts.output = dir;
});
oparser.add('watch', function() {
return opts.watch = true;
});
oparser.add('print', function() {
return opts.print = true;
});
oparser.add('lint', function() {
return opts.lint = true;
});
oparser.add('eval', function() {
return opts.eval = true;
});
oparser.add('tokens', function() {
return opts.tokens = true;
});
oparser.add('tree', function() {
return opts.tree = true;
});
oparser.add('no-wrap', function() {
return opts.no_wrap = true;
});
oparser.add('help', (function(__this) {
var __func = function() {
return usage();
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
oparser.add('version', (function(__this) {
var __func = function() {
return version();
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
paths = oparser.parse(process.ARGV);
return sources = paths.slice(2, paths.length);
option_parser = new optparse.OptionParser(SWITCHES, BANNER);
options = option_parser.parse(process.ARGV);
return sources = options.arguments.slice(2, options.arguments.length);
};
})();
// The options to pass to the CoffeeScript compiler.
compile_options = function compile_options() {
return options['no-wrap'] ? {
no_wrap: true
} : {};
};
})();

View File

@@ -561,4 +561,4 @@
}, {
debug: false
});
})();
})();

View File

@@ -402,4 +402,4 @@
lex.prototype.close_indentation = function close_indentation() {
return this.outdent_token(this.indent);
};
})();
})();

View File

@@ -41,4 +41,4 @@
return factories[topId] = factories[topId] || this.reload(topId, path);
};
require.loader.loaders.unshift([".coffee", loader]);
})();
})();

View File

@@ -1,5 +1,5 @@
(function(){
var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement;
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement;
var __hasProp = Object.prototype.hasOwnProperty;
(typeof process !== "undefined" && process !== null) ? process.mixin(require('scope')) : (this.exports = this);
// Some helper functions
@@ -90,12 +90,12 @@
// generated code should be wrapped up in a closure. An options hash is passed
// and cloned throughout, containing messages from higher in the AST,
// information about the current scope, and indentation level.
Node = (exports.Node = function Node() { });
BaseNode = (exports.BaseNode = function BaseNode() { });
// This is extremely important -- we convert JS statements into expressions
// by wrapping them in a closure, only if it's possible, and we're not at
// the top level of a block (which would be unnecessary), and we haven't
// already been asked to return the result.
Node.prototype.compile = function compile(o) {
BaseNode.prototype.compile = function compile(o) {
var closure, top;
this.options = merge(o || {});
this.indent = o.indent;
@@ -110,21 +110,21 @@
};
// Statements converted into expressions share scope with their parent
// closure, to preserve JavaScript-style lexical scope.
Node.prototype.compile_closure = function compile_closure(o) {
BaseNode.prototype.compile_closure = function compile_closure(o) {
this.indent = o.indent;
o.shared_scope = o.scope;
return ClosureNode.wrap(this).compile(o);
};
// If the code generation wishes to use the result of a complex expression
// in multiple places, ensure that the expression is only ever evaluated once.
Node.prototype.compile_reference = function compile_reference(o) {
BaseNode.prototype.compile_reference = function compile_reference(o) {
var compiled, reference;
reference = new LiteralNode(o.scope.free_variable());
compiled = new AssignNode(reference, this);
return [compiled, reference];
};
// Quick short method for the current indentation level, plus tabbing in.
Node.prototype.idt = function idt(tabs) {
BaseNode.prototype.idt = function idt(tabs) {
var _a, _b, _c, _d, i, idt;
idt = (this.indent || '');
_c = 0; _d = (tabs || 0);
@@ -134,7 +134,7 @@
return idt;
};
// Does this node, or any of its children, contain a node of a certain kind?
Node.prototype.contains = function contains(block) {
BaseNode.prototype.contains = function contains(block) {
var _a, _b, node;
_a = this.children;
for (_b = 0; _b < _a.length; _b++) {
@@ -142,14 +142,14 @@
if (block(node)) {
return true;
}
if (node instanceof Node && node.contains(block)) {
if (node instanceof BaseNode && node.contains(block)) {
return true;
}
}
return false;
};
// toString representation of the node, for inspecting the parse tree.
Node.prototype.toString = function toString(idt) {
BaseNode.prototype.toString = function toString(idt) {
var _a, _b, _c, child;
idt = idt || '';
return '\n' + idt + this.type + (function() {
@@ -162,24 +162,24 @@
}).call(this).join('');
};
// Default implementations of the common node methods.
Node.prototype.unwrap = function unwrap() {
BaseNode.prototype.unwrap = function unwrap() {
return this;
};
Node.prototype.children = [];
Node.prototype.is_statement = function is_statement() {
BaseNode.prototype.children = [];
BaseNode.prototype.is_statement = function is_statement() {
return false;
};
Node.prototype.is_statement_only = function is_statement_only() {
BaseNode.prototype.is_statement_only = function is_statement_only() {
return false;
};
Node.prototype.top_sensitive = function top_sensitive() {
BaseNode.prototype.top_sensitive = function top_sensitive() {
return false;
};
Node.prototype.operation_sensitive = function operation_sensitive() {
BaseNode.prototype.operation_sensitive = function operation_sensitive() {
return false;
};
// A collection of nodes, each one representing an expression.
Expressions = (exports.Expressions = inherit(Node, {
Expressions = (exports.Expressions = inherit(BaseNode, {
type: 'Expressions',
constructor: function constructor(nodes) {
this.children = (this.expressions = compact(flatten(nodes || [])));
@@ -212,7 +212,7 @@
},
compile: function compile(o) {
o = o || {};
return o.scope ? Node.prototype.compile.call(this, o) : this.compile_root(o);
return o.scope ? BaseNode.prototype.compile.call(this, o) : this.compile_root(o);
},
// Compile each expression in the Expressions body.
compile_node: function compile_node(o) {
@@ -233,7 +233,7 @@
o.scope = new Scope(null, this, null);
code = o.globals ? this.compile_node(o) : this.compile_with_declarations(o);
code = code.replace(TRAILING_WHITESPACE, '');
return o.no_wrap ? code : "(function(){\n" + code + "\n})();";
return o.no_wrap ? code : "(function(){\n" + code + "\n})();\n";
},
// Compile the expressions body, with declarations of all inner variables
// pushed up to the top.
@@ -287,7 +287,7 @@
statement(Expressions);
// Literals are static values that can be passed through directly into
// JavaScript without translation, eg.: strings, numbers, true, false, null...
LiteralNode = (exports.LiteralNode = inherit(Node, {
LiteralNode = (exports.LiteralNode = inherit(BaseNode, {
type: 'Literal',
constructor: function constructor(value) {
this.value = value;
@@ -310,7 +310,7 @@
}));
LiteralNode.prototype.is_statement_only = LiteralNode.prototype.is_statement;
// Return an expression, or wrap it in a closure and return it.
ReturnNode = (exports.ReturnNode = inherit(Node, {
ReturnNode = (exports.ReturnNode = inherit(BaseNode, {
type: 'Return',
constructor: function constructor(expression) {
this.children = [(this.expression = expression)];
@@ -327,7 +327,7 @@
}));
statement(ReturnNode, true);
// A value, indexed or dotted into, or vanilla.
ValueNode = (exports.ValueNode = inherit(Node, {
ValueNode = (exports.ValueNode = inherit(BaseNode, {
type: 'Value',
SOAK: " == undefined ? undefined : ",
constructor: function constructor(base, properties) {
@@ -399,7 +399,7 @@
}));
// Pass through CoffeeScript comments into JavaScript comments at the
// same position.
CommentNode = (exports.CommentNode = inherit(Node, {
CommentNode = (exports.CommentNode = inherit(BaseNode, {
type: 'Comment',
constructor: function constructor(lines) {
this.lines = lines;
@@ -412,7 +412,7 @@
statement(CommentNode);
// Node for a function invocation. Takes care of converting super() calls into
// calls against the prototype's function of the same name.
CallNode = (exports.CallNode = inherit(Node, {
CallNode = (exports.CallNode = inherit(BaseNode, {
type: 'Call',
constructor: function constructor(variable, args) {
this.children = flatten([(this.variable = variable), (this.args = (args || []))]);
@@ -477,7 +477,7 @@
}));
// Node to extend an object's prototype with an ancestor object.
// After goog.inherits from the Closure Library.
ExtendsNode = (exports.ExtendsNode = inherit(Node, {
ExtendsNode = (exports.ExtendsNode = inherit(BaseNode, {
type: 'Extends',
constructor: function constructor(child, parent) {
this.children = [(this.child = child), (this.parent = parent)];
@@ -506,7 +506,7 @@
statement(ExtendsNode);
// A dotted accessor into a part of a value, or the :: shorthand for
// an accessor into the object's prototype.
AccessorNode = (exports.AccessorNode = inherit(Node, {
AccessorNode = (exports.AccessorNode = inherit(BaseNode, {
type: 'Accessor',
constructor: function constructor(name, tag) {
this.children = [(this.name = name)];
@@ -519,7 +519,7 @@
}
}));
// An indexed accessor into a part of an array or object.
IndexNode = (exports.IndexNode = inherit(Node, {
IndexNode = (exports.IndexNode = inherit(BaseNode, {
type: 'Index',
constructor: function constructor(index, tag) {
this.children = [(this.index = index)];
@@ -532,7 +532,7 @@
}));
// A range literal. Ranges can be used to extract portions (slices) of arrays,
// or to specify a range for list comprehensions.
RangeNode = (exports.RangeNode = inherit(Node, {
RangeNode = (exports.RangeNode = inherit(BaseNode, {
type: 'Range',
constructor: function constructor(from, to, exclusive) {
this.children = [(this.from = from), (this.to = to)];
@@ -577,7 +577,7 @@
// An array slice literal. Unlike JavaScript's Array#slice, the second parameter
// specifies the index of the end of the slice (just like the first parameter)
// is the index of the beginning.
SliceNode = (exports.SliceNode = inherit(Node, {
SliceNode = (exports.SliceNode = inherit(BaseNode, {
type: 'Slice',
constructor: function constructor(range) {
this.children = [(this.range = range)];
@@ -592,7 +592,7 @@
}
}));
// An object literal.
ObjectNode = (exports.ObjectNode = inherit(Node, {
ObjectNode = (exports.ObjectNode = inherit(BaseNode, {
type: 'Object',
constructor: function constructor(props) {
this.children = (this.objects = (this.properties = props || []));
@@ -639,7 +639,7 @@
}
}));
// An array literal.
ArrayNode = (exports.ArrayNode = inherit(Node, {
ArrayNode = (exports.ArrayNode = inherit(BaseNode, {
type: 'Array',
constructor: function constructor(objects) {
this.children = (this.objects = objects || []);
@@ -694,7 +694,7 @@
}
});
// Setting the value of a local variable, or the value of an object property.
AssignNode = (exports.AssignNode = inherit(Node, {
AssignNode = (exports.AssignNode = inherit(BaseNode, {
type: 'Assign',
PROTO_ASSIGN: /^(\S+)\.prototype/,
LEADING_DOT: /^\.(prototype\.)?/,
@@ -798,7 +798,7 @@
}));
// A function definition. The only node that creates a new Scope.
// A CodeNode does not have any children -- they're within the new scope.
CodeNode = (exports.CodeNode = inherit(Node, {
CodeNode = (exports.CodeNode = inherit(BaseNode, {
type: 'Code',
constructor: function constructor(params, body, tag) {
this.params = params;
@@ -865,7 +865,7 @@
}));
// A splat, either as a parameter to a function, an argument to a call,
// or in a destructuring assignment.
SplatNode = (exports.SplatNode = inherit(Node, {
SplatNode = (exports.SplatNode = inherit(BaseNode, {
type: 'Splat',
constructor: function constructor(name) {
if (!(name.compile)) {
@@ -890,7 +890,7 @@
}));
// A while loop, the only sort of low-level loop exposed by CoffeeScript. From
// it, all other loops can be manufactured.
WhileNode = (exports.WhileNode = inherit(Node, {
WhileNode = (exports.WhileNode = inherit(BaseNode, {
type: 'While',
constructor: function constructor(condition, opts) {
this.children = [(this.condition = condition)];
@@ -933,7 +933,7 @@
statement(WhileNode);
// Simple Arithmetic and logical operations. Performs some conversion from
// CoffeeScript operations into their JavaScript equivalents.
OpNode = (exports.OpNode = inherit(Node, {
OpNode = (exports.OpNode = inherit(BaseNode, {
type: 'Op',
CONVERSIONS: {
'==': '===',
@@ -1019,7 +1019,7 @@
}
}));
// A try/catch/finally block.
TryNode = (exports.TryNode = inherit(Node, {
TryNode = (exports.TryNode = inherit(BaseNode, {
type: 'Try',
constructor: function constructor(attempt, error, recovery, ensure) {
this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]);
@@ -1040,7 +1040,7 @@
}));
statement(TryNode);
// Throw an exception.
ThrowNode = (exports.ThrowNode = inherit(Node, {
ThrowNode = (exports.ThrowNode = inherit(BaseNode, {
type: 'Throw',
constructor: function constructor(expression) {
this.children = [(this.expression = expression)];
@@ -1052,7 +1052,7 @@
}));
statement(ThrowNode, true);
// Check an expression for existence (meaning not null or undefined).
ExistenceNode = (exports.ExistenceNode = inherit(Node, {
ExistenceNode = (exports.ExistenceNode = inherit(BaseNode, {
type: 'Existence',
constructor: function constructor(expression) {
this.children = [(this.expression = expression)];
@@ -1075,7 +1075,7 @@
return '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)';
};
// An extra set of parentheses, specified explicitly in the source.
ParentheticalNode = (exports.ParentheticalNode = inherit(Node, {
ParentheticalNode = (exports.ParentheticalNode = inherit(BaseNode, {
type: 'Paren',
constructor: function constructor(expression) {
this.children = [(this.expression = expression)];
@@ -1101,7 +1101,7 @@
// into a for loop. Also acts as an expression, able to return the result
// of the comprehenion. Unlike Python array comprehensions, it's able to pass
// the current index of the loop as a second parameter.
ForNode = (exports.ForNode = inherit(Node, {
ForNode = (exports.ForNode = inherit(BaseNode, {
type: 'For',
constructor: function constructor(body, source, name, index) {
var _a;
@@ -1199,7 +1199,7 @@
// expression by pushing down requested returns to the expression bodies.
// Single-expression IfNodes are compiled into ternary operators if possible,
// because ternaries are first-class returnable assignable expressions.
IfNode = (exports.IfNode = inherit(Node, {
IfNode = (exports.IfNode = inherit(BaseNode, {
type: 'If',
constructor: function constructor(condition, body, else_body, tags) {
this.condition = condition;
@@ -1325,4 +1325,4 @@
return if_part + ' : ' + else_part;
}
}));
})();
})();

View File

@@ -1,21 +1,19 @@
(function(){
var LONG_FLAG, OPTIONAL, SHORT_FLAG, build_rule, build_rules, op, spaces;
// Create an OptionParser with a list of valid options.
op = (exports.OptionParser = function OptionParser(rules) {
this.banner = 'Usage: [Options]';
op = (exports.OptionParser = function OptionParser(rules, banner) {
this.banner = banner || 'Usage: [Options]';
this.options_title = 'Available options:';
this.rules = build_rules(rules);
this.actions = {};
return this;
});
// Add a callback to fire when a particular option is encountered.
op.prototype.add = function add(value, callback) {
return this.actions[value] = callback;
};
// Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op.prototype.parse = function parse(args) {
var _a, _b, arg, callback, is_option, results, rule, value;
results = [];
var _a, _b, arg, is_option, options, rule;
arguments = Array.prototype.slice.call(arguments, 0);
options = {
arguments: []
};
args = args.concat([]);
while (((arg = args.shift()))) {
is_option = false;
@@ -23,20 +21,16 @@
for (_b = 0; _b < _a.length; _b++) {
rule = _a[_b];
if (rule.letter === arg || rule.flag === arg) {
callback = this.actions[rule.name];
value = rule.argument && args.shift();
if (callback) {
callback(value);
}
options[rule.name] = rule.argument ? args.shift() : true;
is_option = true;
break;
}
}
if (!(is_option)) {
results.push(arg);
options.arguments.push(arg);
}
}
return results;
return options;
};
// Return the help text for this OptionParser, for --help and such.
op.prototype.help = function help() {
@@ -114,4 +108,4 @@
}
return builder.join('');
};
})();
})();

View File

@@ -29,4 +29,4 @@
process.stdio.addListener('data', readline);
process.stdio.open();
print(prompt);
})();
})();

View File

@@ -380,4 +380,4 @@
});
})(this));
};
})();
})();

View File

@@ -111,4 +111,4 @@
Scope.prototype.compiled_assignments = function compiled_assignments() {
return this.assigned_variables().join(', ');
};
})();
})();

View File

@@ -3,5 +3,5 @@
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language"],
"author": "Jeremy Ashkenas",
"version": "0.5.1"
"version": "0.5.2"
}

View File

@@ -24,7 +24,7 @@ parser.lexer: {
showPosition: -> @pos
}
exports.VERSION: '0.5.1'
exports.VERSION: '0.5.2'
# Compile CoffeeScript to JavaScript, using the Coffee/Jison compiler.
exports.compile: (code, options) ->
@@ -38,8 +38,8 @@ exports.tokenize: (code) ->
exports.tree: (code) ->
parser.parse lexer.tokenize code
# Pretty-print a token stream.
exports.print_tokens: (tokens) ->
strings: for token in tokens
'[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']'
puts strings.join(' ')
# Activate CoffeeScript in the browser by having it compile and eval
# all script tags with a content-type of text/coffeescript.
if document? and document.getElementsByTagName
for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
eval exports.compile tag.innerHTML

View File

@@ -1,7 +1,7 @@
fs: require 'fs'
path: require 'path'
coffee: require 'coffee-script'
optparse: require('optparse')
fs: require 'fs'
path: require 'path'
optparse: require 'optparse'
CoffeeScript: require 'coffee-script'
BANNER: '''
coffee compiles CoffeeScript source files into JavaScript.
@@ -17,10 +17,11 @@ SWITCHES: [
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
['-s', '--stdio', 'listen for and compile scripts over stdio']
['-e', '--eval', 'compile a string from the command line']
['-n', '--no-wrap', 'compile without the top-level function wrapper']
['-t', '--tokens', 'print the tokens that the lexer produces']
['-tr','--tree', 'print the parse tree that Jison produces']
['-n', '--no-wrap', 'compile without the top-level function wrapper']
['-v', '--version', 'display CoffeeScript version']
['-h', '--help', 'display this help message']
]
@@ -32,9 +33,12 @@ option_parser: null
# The CommandLine handles all of the functionality of the `coffee` utility.
exports.run: ->
parse_options()
return require 'repl' if options.interactive
return compile_script 'terminal', sources[0] if options.eval
usage() unless sources.length
return usage() if options.help
return version() if options.version
return require 'repl' if options.interactive
return compile_stdio() if options.stdio
return compile_script 'unknown', sources[0] if options.eval
return usage() unless sources.length
separator: sources.indexOf '--'
flags: []
if separator >= 0
@@ -52,7 +56,7 @@ usage: ->
# The "--version" message.
version: ->
puts "CoffeeScript version " + coffee.VERSION
puts "CoffeeScript version " + CoffeeScript.VERSION
process.exit 0
# Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
@@ -62,23 +66,30 @@ compile_scripts: ->
fs.readFile source, (err, code) -> compile_script(source, code)
compile(source) for source in sources
# Compile a single source script, containing the given code, according to the
# requested options. Both compile_scripts and watch_scripts share this method.
compile_script: (source, code) ->
opts: options
o: if opts.no_wrap then {no_wrap: true} else {}
o: options
try
if opts.tokens then coffee.print_tokens coffee.tokenize code
else if opts.tree then puts coffee.tree(code).toString()
if o.tokens then print_tokens CoffeeScript.tokenize code
else if o.tree then puts CoffeeScript.tree(code).toString()
else
js: coffee.compile code, o
if opts.run then eval js
else if opts.lint then lint js
else if opts.print or opts.eval then puts js
else write_js source, js
js: CoffeeScript.compile code, compile_options()
if o.run then eval js
else if o.lint then lint js
else if o.print or o.eval then print js
else write_js source, js
catch err
if opts.watch then puts err.message else throw err
if o.watch then puts err.message else throw err
# Listen for and compile scripts over stdio.
compile_stdio: ->
code: ''
process.stdio.open()
process.stdio.addListener 'data', (string) ->
code += string if string
process.stdio.addListener 'close', ->
process.stdio.write CoffeeScript.compile code, compile_options()
# Watch a list of source CoffeeScript files, recompiling them every time the
# files are updated.
@@ -106,25 +117,18 @@ lint: (js) ->
jsl.write js
jsl.close()
# Pretty-print a token stream.
print_tokens: (tokens) ->
strings: for token in tokens
'[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']'
puts strings.join(' ')
# Use OptionParser for all the options.
parse_options: ->
opts: options: {}
oparser: option_parser: new optparse.OptionParser SWITCHES
oparser.banner: BANNER
oparser.add 'interactive', -> opts.interactive: true
oparser.add 'run', -> opts.run: true
oparser.add 'output', (dir) -> opts.output: dir
oparser.add 'watch', -> opts.watch: true
oparser.add 'print', -> opts.print: true
oparser.add 'lint', -> opts.lint: true
oparser.add 'eval', -> opts.eval: true
oparser.add 'tokens', -> opts.tokens: true
oparser.add 'tree', -> opts.tree: true
oparser.add 'no-wrap', -> opts.no_wrap: true
oparser.add 'help', => usage()
oparser.add 'version', => version()
paths: oparser.parse(process.ARGV)
sources: paths[2...paths.length]
option_parser: new optparse.OptionParser SWITCHES, BANNER
options: option_parser.parse(process.ARGV)
sources: options.arguments[2...options.arguments.length]
# The options to pass to the CoffeeScript compiler.
compile_options: ->
if options['no-wrap'] then {no_wrap: true} else {}

View File

@@ -54,13 +54,13 @@ statement: (klass, only) ->
# generated code should be wrapped up in a closure. An options hash is passed
# and cloned throughout, containing messages from higher in the AST,
# information about the current scope, and indentation level.
Node: exports.Node: ->
BaseNode: exports.BaseNode: ->
# This is extremely important -- we convert JS statements into expressions
# by wrapping them in a closure, only if it's possible, and we're not at
# the top level of a block (which would be unnecessary), and we haven't
# already been asked to return the result.
Node::compile: (o) ->
BaseNode::compile: (o) ->
@options: merge o or {}
@indent: o.indent
del @options, 'operation' unless @operation_sensitive()
@@ -72,46 +72,46 @@ Node::compile: (o) ->
# Statements converted into expressions share scope with their parent
# closure, to preserve JavaScript-style lexical scope.
Node::compile_closure: (o) ->
BaseNode::compile_closure: (o) ->
@indent: o.indent
o.shared_scope: o.scope
ClosureNode.wrap(this).compile(o)
# If the code generation wishes to use the result of a complex expression
# in multiple places, ensure that the expression is only ever evaluated once.
Node::compile_reference: (o) ->
BaseNode::compile_reference: (o) ->
reference: new LiteralNode(o.scope.free_variable())
compiled: new AssignNode(reference, this)
[compiled, reference]
# Quick short method for the current indentation level, plus tabbing in.
Node::idt: (tabs) ->
BaseNode::idt: (tabs) ->
idt: (@indent || '')
idt += TAB for i in [0...(tabs or 0)]
idt
# Does this node, or any of its children, contain a node of a certain kind?
Node::contains: (block) ->
BaseNode::contains: (block) ->
for node in @children
return true if block(node)
return true if node instanceof Node and node.contains block
return true if node instanceof BaseNode and node.contains block
false
# toString representation of the node, for inspecting the parse tree.
Node::toString: (idt) ->
BaseNode::toString: (idt) ->
idt ||= ''
'\n' + idt + @type + (child.toString(idt + TAB) for child in @children).join('')
# Default implementations of the common node methods.
Node::unwrap: -> this
Node::children: []
Node::is_statement: -> false
Node::is_statement_only: -> false
Node::top_sensitive: -> false
Node::operation_sensitive: -> false
BaseNode::unwrap: -> this
BaseNode::children: []
BaseNode::is_statement: -> false
BaseNode::is_statement_only: -> false
BaseNode::top_sensitive: -> false
BaseNode::operation_sensitive: -> false
# A collection of nodes, each one representing an expression.
Expressions: exports.Expressions: inherit Node, {
Expressions: exports.Expressions: inherit BaseNode, {
type: 'Expressions'
constructor: (nodes) ->
@@ -144,7 +144,7 @@ Expressions: exports.Expressions: inherit Node, {
compile: (o) ->
o ||= {}
if o.scope then Node::compile.call(this, o) else @compile_root(o)
if o.scope then BaseNode::compile.call(this, o) else @compile_root(o)
# Compile each expression in the Expressions body.
compile_node: (o) ->
@@ -156,7 +156,7 @@ Expressions: exports.Expressions: inherit Node, {
o.scope: new Scope(null, this, null)
code: if o.globals then @compile_node(o) else @compile_with_declarations(o)
code: code.replace(TRAILING_WHITESPACE, '')
if o.no_wrap then code else "(function(){\n"+code+"\n})();"
if o.no_wrap then code else "(function(){\n"+code+"\n})();\n"
# Compile the expressions body, with declarations of all inner variables
# pushed up to the top.
@@ -192,7 +192,7 @@ statement Expressions
# Literals are static values that can be passed through directly into
# JavaScript without translation, eg.: strings, numbers, true, false, null...
LiteralNode: exports.LiteralNode: inherit Node, {
LiteralNode: exports.LiteralNode: inherit BaseNode, {
type: 'Literal'
constructor: (value) ->
@@ -217,7 +217,7 @@ LiteralNode: exports.LiteralNode: inherit Node, {
LiteralNode::is_statement_only: LiteralNode::is_statement
# Return an expression, or wrap it in a closure and return it.
ReturnNode: exports.ReturnNode: inherit Node, {
ReturnNode: exports.ReturnNode: inherit BaseNode, {
type: 'Return'
constructor: (expression) ->
@@ -233,7 +233,7 @@ ReturnNode: exports.ReturnNode: inherit Node, {
statement ReturnNode, true
# A value, indexed or dotted into, or vanilla.
ValueNode: exports.ValueNode: inherit Node, {
ValueNode: exports.ValueNode: inherit BaseNode, {
type: 'Value'
SOAK: " == undefined ? undefined : "
@@ -302,7 +302,7 @@ ValueNode: exports.ValueNode: inherit Node, {
# Pass through CoffeeScript comments into JavaScript comments at the
# same position.
CommentNode: exports.CommentNode: inherit Node, {
CommentNode: exports.CommentNode: inherit BaseNode, {
type: 'Comment'
constructor: (lines) ->
@@ -318,7 +318,7 @@ statement CommentNode
# Node for a function invocation. Takes care of converting super() calls into
# calls against the prototype's function of the same name.
CallNode: exports.CallNode: inherit Node, {
CallNode: exports.CallNode: inherit BaseNode, {
type: 'Call'
constructor: (variable, args) ->
@@ -366,7 +366,7 @@ CallNode: exports.CallNode: inherit Node, {
# Node to extend an object's prototype with an ancestor object.
# After goog.inherits from the Closure Library.
ExtendsNode: exports.ExtendsNode: inherit Node, {
ExtendsNode: exports.ExtendsNode: inherit BaseNode, {
type: 'Extends'
constructor: (child, parent) ->
@@ -399,7 +399,7 @@ statement ExtendsNode
# A dotted accessor into a part of a value, or the :: shorthand for
# an accessor into the object's prototype.
AccessorNode: exports.AccessorNode: inherit Node, {
AccessorNode: exports.AccessorNode: inherit BaseNode, {
type: 'Accessor'
constructor: (name, tag) ->
@@ -414,7 +414,7 @@ AccessorNode: exports.AccessorNode: inherit Node, {
}
# An indexed accessor into a part of an array or object.
IndexNode: exports.IndexNode: inherit Node, {
IndexNode: exports.IndexNode: inherit BaseNode, {
type: 'Index'
constructor: (index, tag) ->
@@ -429,7 +429,7 @@ IndexNode: exports.IndexNode: inherit Node, {
# A range literal. Ranges can be used to extract portions (slices) of arrays,
# or to specify a range for list comprehensions.
RangeNode: exports.RangeNode: inherit Node, {
RangeNode: exports.RangeNode: inherit BaseNode, {
type: 'Range'
constructor: (from, to, exclusive) ->
@@ -469,7 +469,7 @@ RangeNode: exports.RangeNode: inherit Node, {
# An array slice literal. Unlike JavaScript's Array#slice, the second parameter
# specifies the index of the end of the slice (just like the first parameter)
# is the index of the beginning.
SliceNode: exports.SliceNode: inherit Node, {
SliceNode: exports.SliceNode: inherit BaseNode, {
type: 'Slice'
constructor: (range) ->
@@ -485,7 +485,7 @@ SliceNode: exports.SliceNode: inherit Node, {
}
# An object literal.
ObjectNode: exports.ObjectNode: inherit Node, {
ObjectNode: exports.ObjectNode: inherit BaseNode, {
type: 'Object'
constructor: (props) ->
@@ -512,7 +512,7 @@ ObjectNode: exports.ObjectNode: inherit Node, {
}
# An array literal.
ArrayNode: exports.ArrayNode: inherit Node, {
ArrayNode: exports.ArrayNode: inherit BaseNode, {
type: 'Array'
constructor: (objects) ->
@@ -559,7 +559,7 @@ ClosureNode: exports.ClosureNode: {
}
# Setting the value of a local variable, or the value of an object property.
AssignNode: exports.AssignNode: inherit Node, {
AssignNode: exports.AssignNode: inherit BaseNode, {
type: 'Assign'
PROTO_ASSIGN: /^(\S+)\.prototype/
@@ -632,7 +632,7 @@ AssignNode: exports.AssignNode: inherit Node, {
# A function definition. The only node that creates a new Scope.
# A CodeNode does not have any children -- they're within the new scope.
CodeNode: exports.CodeNode: inherit Node, {
CodeNode: exports.CodeNode: inherit BaseNode, {
type: 'Code'
constructor: (params, body, tag) ->
@@ -676,7 +676,7 @@ CodeNode: exports.CodeNode: inherit Node, {
# A splat, either as a parameter to a function, an argument to a call,
# or in a destructuring assignment.
SplatNode: exports.SplatNode: inherit Node, {
SplatNode: exports.SplatNode: inherit BaseNode, {
type: 'Splat'
constructor: (name) ->
@@ -699,7 +699,7 @@ SplatNode: exports.SplatNode: inherit Node, {
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
# it, all other loops can be manufactured.
WhileNode: exports.WhileNode: inherit Node, {
WhileNode: exports.WhileNode: inherit BaseNode, {
type: 'While'
constructor: (condition, opts) ->
@@ -737,7 +737,7 @@ statement WhileNode
# Simple Arithmetic and logical operations. Performs some conversion from
# CoffeeScript operations into their JavaScript equivalents.
OpNode: exports.OpNode: inherit Node, {
OpNode: exports.OpNode: inherit BaseNode, {
type: 'Op'
CONVERSIONS: {
@@ -801,7 +801,7 @@ OpNode: exports.OpNode: inherit Node, {
}
# A try/catch/finally block.
TryNode: exports.TryNode: inherit Node, {
TryNode: exports.TryNode: inherit BaseNode, {
type: 'Try'
constructor: (attempt, error, recovery, ensure) ->
@@ -822,7 +822,7 @@ TryNode: exports.TryNode: inherit Node, {
statement TryNode
# Throw an exception.
ThrowNode: exports.ThrowNode: inherit Node, {
ThrowNode: exports.ThrowNode: inherit BaseNode, {
type: 'Throw'
constructor: (expression) ->
@@ -837,7 +837,7 @@ ThrowNode: exports.ThrowNode: inherit Node, {
statement ThrowNode, true
# Check an expression for existence (meaning not null or undefined).
ExistenceNode: exports.ExistenceNode: inherit Node, {
ExistenceNode: exports.ExistenceNode: inherit BaseNode, {
type: 'Existence'
constructor: (expression) ->
@@ -856,7 +856,7 @@ ExistenceNode.compile_test: (o, variable) ->
'(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)'
# An extra set of parentheses, specified explicitly in the source.
ParentheticalNode: exports.ParentheticalNode: inherit Node, {
ParentheticalNode: exports.ParentheticalNode: inherit BaseNode, {
type: 'Paren'
constructor: (expression) ->
@@ -879,7 +879,7 @@ ParentheticalNode: exports.ParentheticalNode: inherit Node, {
# into a for loop. Also acts as an expression, able to return the result
# of the comprehenion. Unlike Python array comprehensions, it's able to pass
# the current index of the loop as a second parameter.
ForNode: exports.ForNode: inherit Node, {
ForNode: exports.ForNode: inherit BaseNode, {
type: 'For'
constructor: (body, source, name, index) ->
@@ -949,7 +949,7 @@ statement ForNode
# expression by pushing down requested returns to the expression bodies.
# Single-expression IfNodes are compiled into ternary operators if possible,
# because ternaries are first-class returnable assignable expressions.
IfNode: exports.IfNode: inherit Node, {
IfNode: exports.IfNode: inherit BaseNode, {
type: 'If'
constructor: (condition, body, else_body, tags) ->

View File

@@ -1,30 +1,23 @@
# Create an OptionParser with a list of valid options.
op: exports.OptionParser: (rules) ->
@banner: 'Usage: [Options]'
op: exports.OptionParser: (rules, banner) ->
@banner: banner or 'Usage: [Options]'
@options_title: 'Available options:'
@rules: build_rules(rules)
@actions: {}
this
# Add a callback to fire when a particular option is encountered.
op::add: (value, callback) ->
@actions[value]: callback
# Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op::parse: (args) ->
results: []
options: {arguments: []}
args: args.concat []
while (arg: args.shift())
is_option: false
for rule in @rules
if rule.letter is arg or rule.flag is arg
callback: @actions[rule.name]
value: rule.argument and args.shift()
callback(value) if callback
options[rule.name]: if rule.argument then args.shift() else true
is_option: true
break
results.push arg unless is_option
results
options.arguments.push arg unless is_option
options
# Return the help text for this OptionParser, for --help and such.
op::help: ->