mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 09:17:55 -05:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dc932e380 | ||
|
|
a71de4b5b6 | ||
|
|
ada8dfc6d4 | ||
|
|
4112595368 | ||
|
|
c281db7730 | ||
|
|
5e6b49ad1e | ||
|
|
ec1a527575 | ||
|
|
dc0ab1afca | ||
|
|
ae72fbfd0d | ||
|
|
ad0735f765 | ||
|
|
d49c178f1d | ||
|
|
8f8ba255b3 | ||
|
|
a4bc24817d | ||
|
|
9eeac9b272 | ||
|
|
f859eb6cec | ||
|
|
b29afc2c09 |
3
bin/cs
Executable file
3
bin/cs
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env narwhal
|
||||
|
||||
require("coffee-script").run(system.args);
|
||||
@@ -1,12 +1,17 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = 'coffee-script'
|
||||
s.version = '0.1.0' # Keep version in sync with coffee-script.rb
|
||||
s.version = '0.1.2' # Keep version in sync with coffee-script.rb
|
||||
s.date = '2009-12-24'
|
||||
|
||||
s.homepage = "http://jashkenas.github.com/coffee-script/"
|
||||
s.summary = "The CoffeeScript Compiler"
|
||||
s.description = <<-EOS
|
||||
CoffeeScript is a little language that compiles into JavaScript.
|
||||
CoffeeScript is a little language that compiles into JavaScript. Think
|
||||
of it as JavaScript's less ostentatious kid brother -- the same genes,
|
||||
roughly the same height, but a different sense of style. Apart from a
|
||||
handful of bonus goodies, statements in CoffeeScript correspond
|
||||
one-to-one with their equivalent in JavaScript, it's just another
|
||||
way of saying it.
|
||||
EOS
|
||||
|
||||
s.authors = ['Jeremy Ashkenas']
|
||||
|
||||
@@ -3,13 +3,13 @@ Animal.prototype.move: meters =>
|
||||
alert(this.name + " moved " + meters + "m.").
|
||||
|
||||
Snake: name => this.name: name.
|
||||
Snake.prototype: new Animal()
|
||||
Snake extends new Animal()
|
||||
Snake.prototype.move: =>
|
||||
alert("Slithering...")
|
||||
super(5).
|
||||
|
||||
Horse: name => this.name: name.
|
||||
Horse.prototype: new Animal()
|
||||
Horse extends new Animal()
|
||||
Horse.prototype.move: =>
|
||||
alert("Galloping...")
|
||||
super(45).
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<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="#super">Calling Super from a Subclass</a><br />
|
||||
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
|
||||
<a href="#embedded">Embedded JavaScript</a><br />
|
||||
<a href="#switch">Switch/When/Else</a><br />
|
||||
<a href="#try">Try/Catch/Finally</a><br />
|
||||
@@ -283,6 +283,10 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
|
||||
<p>
|
||||
You can use <tt>not</tt> as an alias for <tt>!</tt>.
|
||||
</p>
|
||||
<p>
|
||||
For logic, <tt>and</tt> compiles to <tt>&&</tt>, and <tt>or</tt>
|
||||
into <tt>||</tt>.
|
||||
</p>
|
||||
<p>
|
||||
Instead of a newline or semicolon, <tt>then</tt> can be used to separate
|
||||
conditions from expressions, in <b>while</b>,
|
||||
@@ -328,8 +332,8 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
|
||||
</p>
|
||||
<%= code_for('slices', 'three_to_six') %>
|
||||
|
||||
<p id="super">
|
||||
<b class="header">Calling Super from a Subclass</b>
|
||||
<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 that provide a cleaner
|
||||
syntax for classical inheritance on top of JavaScript's prototypes:
|
||||
@@ -337,9 +341,11 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
|
||||
<a href="http://prototypejs.org/">Prototype.js</a>,
|
||||
<a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc.
|
||||
The libraries provide syntactic sugar, but the built-in inheritance would
|
||||
be completely usable if it weren't for one small exception:
|
||||
it's very awkward to call <b>super</b>, the prototype object's
|
||||
implementation of the current function. CoffeeScript converts
|
||||
be completely usable if it weren't for a couple of small exceptions:
|
||||
it's awkward to call <b>super</b> (the prototype object's
|
||||
implementation of the current function), and it's awkward to correctly
|
||||
set the prototype chain. CoffeeScript provides <tt>extends</tt>
|
||||
to help with prototype setup, and converts
|
||||
<tt>super()</tt> calls into calls against the immediate ancestor's
|
||||
method of the same name.
|
||||
</p>
|
||||
@@ -405,12 +411,34 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre>
|
||||
Integration with Processing.js's JavaScript API (this would depend on
|
||||
having a JavaScript version of the compiler).
|
||||
</li>
|
||||
<li>
|
||||
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
|
||||
string manipulation. Techniques for cleaning this up across the board
|
||||
would be appreciated.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="change_log">Change Log</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 25px;">0.1.0</b>
|
||||
<b class="header" style="margin-top: 20px;">0.1.2</b>
|
||||
Fixed a bug with calling <tt>super()</tt> through more than one level of
|
||||
inheritance, with the re-addition of the <tt>extends</tt> keyword.
|
||||
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
|
||||
support (as a Tusk package), contributed by
|
||||
<a href="http://tlrobinson.net/">Tom Robinson</a>, including
|
||||
<b>bin/cs</b> as a CoffeeScript REPL and interpreter.
|
||||
New <tt>--no-wrap</tt> option to suppress the safety function
|
||||
wrapper.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.1.1</b>
|
||||
Added <tt>instanceof</tt> and <tt>typeof</tt> as operators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.1.0</b>
|
||||
Initial CoffeeScript release.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
this.name = name;
|
||||
return this.name;
|
||||
};
|
||||
Snake.prototype = new Animal();
|
||||
Snake.prototype.__proto__ = new Animal();
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return this.constructor.prototype.move.call(this, 5);
|
||||
return Snake.prototype.__proto__.move.call(this, 5);
|
||||
};
|
||||
var Horse = function(name) {
|
||||
this.name = name;
|
||||
return this.name;
|
||||
};
|
||||
Horse.prototype = new Animal();
|
||||
Horse.prototype.__proto__ = new Animal();
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return this.constructor.prototype.move.call(this, 45);
|
||||
return Horse.prototype.__proto__.move.call(this, 45);
|
||||
};
|
||||
var sam = new Snake("Sammy the Python");
|
||||
var tom = new Horse("Tommy the Palomino");
|
||||
|
||||
@@ -145,13 +145,13 @@ Animal.prototype.move: meters =>
|
||||
alert(this.name + " moved " + meters + "m.").
|
||||
|
||||
Snake: name => this.name: name.
|
||||
Snake.prototype: Animal
|
||||
Snake extends new Animal()
|
||||
Snake.prototype.move: =>
|
||||
alert('Slithering...')
|
||||
super(5).
|
||||
|
||||
Horse: name => this.name: name.
|
||||
Horse.prototype: Animal
|
||||
Horse extends new Animal()
|
||||
Horse.prototype.move: =>
|
||||
alert('Galloping...')
|
||||
super(45).
|
||||
|
||||
62
index.html
62
index.html
@@ -53,7 +53,7 @@
|
||||
<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="#super">Calling Super from a Subclass</a><br />
|
||||
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
|
||||
<a href="#embedded">Embedded JavaScript</a><br />
|
||||
<a href="#switch">Switch/When/Else</a><br />
|
||||
<a href="#try">Try/Catch/Finally</a><br />
|
||||
@@ -458,6 +458,10 @@ var eldest = 24 > 21 ? "Liz" : "Ike";
|
||||
<p>
|
||||
You can use <tt>not</tt> as an alias for <tt>!</tt>.
|
||||
</p>
|
||||
<p>
|
||||
For logic, <tt>and</tt> compiles to <tt>&&</tt>, and <tt>or</tt>
|
||||
into <tt>||</tt>.
|
||||
</p>
|
||||
<p>
|
||||
Instead of a newline or semicolon, <tt>then</tt> can be used to separate
|
||||
conditions from expressions, in <b>while</b>,
|
||||
@@ -561,8 +565,8 @@ 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="super">
|
||||
<b class="header">Calling Super from a Subclass</b>
|
||||
<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 that provide a cleaner
|
||||
syntax for classical inheritance on top of JavaScript's prototypes:
|
||||
@@ -570,9 +574,11 @@ var three_to_six = nums.slice(3, 6 + 1);
|
||||
<a href="http://prototypejs.org/">Prototype.js</a>,
|
||||
<a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc.
|
||||
The libraries provide syntactic sugar, but the built-in inheritance would
|
||||
be completely usable if it weren't for one small exception:
|
||||
it's very awkward to call <b>super</b>, the prototype object's
|
||||
implementation of the current function. CoffeeScript converts
|
||||
be completely usable if it weren't for a couple of small exceptions:
|
||||
it's awkward to call <b>super</b> (the prototype object's
|
||||
implementation of the current function), and it's awkward to correctly
|
||||
set the prototype chain. CoffeeScript provides <tt>extends</tt>
|
||||
to help with prototype setup, and converts
|
||||
<tt>super()</tt> calls into calls against the immediate ancestor's
|
||||
method of the same name.
|
||||
</p>
|
||||
@@ -581,13 +587,13 @@ var three_to_six = nums.slice(3, 6 + 1);
|
||||
alert(<span class="Variable">this</span>.name <span class="Keyword">+</span> <span class="String"><span class="String">"</span> moved <span class="String">"</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">"</span>m.<span class="String">"</span></span>).
|
||||
|
||||
<span class="FunctionName">Snake</span><span class="Keyword">:</span> <span class="FunctionArgument">name</span> <span class="Storage">=></span> <span class="Variable">this</span>.name<span class="Keyword">:</span> name.
|
||||
Snake.prototype<span class="Keyword">:</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
|
||||
Snake <span class="Variable">extends</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
|
||||
<span class="FunctionName">Snake.prototype.move</span><span class="Keyword">:</span> <span class="Storage">=></span>
|
||||
alert(<span class="String"><span class="String">"</span>Slithering...<span class="String">"</span></span>)
|
||||
<span class="Variable">super</span>(<span class="Number">5</span>).
|
||||
|
||||
<span class="FunctionName">Horse</span><span class="Keyword">:</span> <span class="FunctionArgument">name</span> <span class="Storage">=></span> <span class="Variable">this</span>.name<span class="Keyword">:</span> name.
|
||||
Horse.prototype<span class="Keyword">:</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
|
||||
Horse <span class="Variable">extends</span> <span class="Keyword">new</span> <span class="TypeName">Animal</span>()
|
||||
<span class="FunctionName">Horse.prototype.move</span><span class="Keyword">:</span> <span class="Storage">=></span>
|
||||
alert(<span class="String"><span class="String">"</span>Galloping...<span class="String">"</span></span>)
|
||||
<span class="Variable">super</span>(<span class="Number">45</span>).
|
||||
@@ -610,19 +616,19 @@ tom.move()
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">name</span>;
|
||||
};
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">__proto__</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Slithering...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">constructor</span>.<span class="LibraryConstant">prototype</span>.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
|
||||
<span class="Keyword">return</span> Snake.<span class="LibraryConstant">prototype</span>.__proto__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
|
||||
};
|
||||
<span class="Storage">var</span> <span class="FunctionName">Horse</span> = <span class="Storage">function</span>(<span class="FunctionArgument">name</span>) {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">name</span>;
|
||||
};
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">__proto__</span> = <span class="Keyword">new</span> <span class="TypeName">Animal</span>();
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Galloping...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryConstant">constructor</span>.<span class="LibraryConstant">prototype</span>.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
|
||||
<span class="Keyword">return</span> Horse.<span class="LibraryConstant">prototype</span>.__proto__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
|
||||
};
|
||||
<span class="Storage">var</span> sam <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Snake</span>(<span class="String"><span class="String">"</span>Sammy the Python<span class="String">"</span></span>);
|
||||
<span class="Storage">var</span> tom <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Horse</span>(<span class="String"><span class="String">"</span>Tommy the Palomino<span class="String">"</span></span>);
|
||||
@@ -637,19 +643,19 @@ var Snake = function(name) {
|
||||
this.name = name;
|
||||
return this.name;
|
||||
};
|
||||
Snake.prototype = new Animal();
|
||||
Snake.prototype.__proto__ = new Animal();
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return this.constructor.prototype.move.call(this, 5);
|
||||
return Snake.prototype.__proto__.move.call(this, 5);
|
||||
};
|
||||
var Horse = function(name) {
|
||||
this.name = name;
|
||||
return this.name;
|
||||
};
|
||||
Horse.prototype = new Animal();
|
||||
Horse.prototype.__proto__ = new Animal();
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return this.constructor.prototype.move.call(this, 45);
|
||||
return Horse.prototype.__proto__.move.call(this, 45);
|
||||
};
|
||||
var sam = new Snake("Sammy the Python");
|
||||
var tom = new Horse("Tommy the Palomino");
|
||||
@@ -784,12 +790,34 @@ world...";
|
||||
Integration with Processing.js's JavaScript API (this would depend on
|
||||
having a JavaScript version of the compiler).
|
||||
</li>
|
||||
<li>
|
||||
A lot of the code generation in <tt>nodes.rb</tt> gets into messy
|
||||
string manipulation. Techniques for cleaning this up across the board
|
||||
would be appreciated.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="change_log">Change Log</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 25px;">0.1.0</b>
|
||||
<b class="header" style="margin-top: 20px;">0.1.2</b>
|
||||
Fixed a bug with calling <tt>super()</tt> through more than one level of
|
||||
inheritance, with the re-addition of the <tt>extends</tt> keyword.
|
||||
Added experimental <a href="http://narwhaljs.org/">Narwhal</a>
|
||||
support (as a Tusk package), contributed by
|
||||
<a href="http://tlrobinson.net/">Tom Robinson</a>, including
|
||||
<b>bin/cs</b> as a CoffeeScript REPL and interpreter.
|
||||
New <tt>--no-wrap</tt> option to suppress the safety function
|
||||
wrapper.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.1.1</b>
|
||||
Added <tt>instanceof</tt> and <tt>typeof</tt> as operators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.1.0</b>
|
||||
Initial CoffeeScript release.
|
||||
</p>
|
||||
|
||||
|
||||
91
lib-js/coffee-script.js
Normal file
91
lib-js/coffee-script.js
Normal file
@@ -0,0 +1,91 @@
|
||||
var FILE = require("file");
|
||||
var OS = require("os");
|
||||
|
||||
exports.run = function(args) {
|
||||
// TODO: non-REPL
|
||||
|
||||
args.shift();
|
||||
|
||||
if (args.length) {
|
||||
require(FILE.absolute(args[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
try {
|
||||
system.stdout.write("cs> ").flush();
|
||||
|
||||
var result = exports.cs_eval(require("readline").readline());
|
||||
|
||||
if (result !== undefined)
|
||||
print(result);
|
||||
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// executes the coffee-script Ruby program to convert from CoffeeScript to Objective-J.
|
||||
// eventually this will hopefully be replaced by a JavaScript program.
|
||||
var coffeePath = FILE.path(module.path).dirname().dirname().join("bin", "coffee-script");
|
||||
|
||||
exports.compileFile = function(path) {
|
||||
var coffee = OS.popen([coffeePath, "--print", path]);
|
||||
|
||||
if (coffee.wait() !== 0)
|
||||
throw new Error("coffee compiler error");
|
||||
|
||||
return coffee.stdout.read();
|
||||
}
|
||||
|
||||
exports.compile = function(source) {
|
||||
var coffee = OS.popen([coffeePath, "-e"]);
|
||||
|
||||
coffee.stdin.write(source).flush().close();
|
||||
|
||||
if (coffee.wait() !== 0)
|
||||
throw new Error("coffee compiler error");
|
||||
|
||||
return coffee.stdout.read();
|
||||
}
|
||||
|
||||
// these two functions are equivalent to objective-j's objj_eval/make_narwhal_factory.
|
||||
// implemented as a call to coffee and objj_eval/make_narwhal_factory
|
||||
exports.cs_eval = function(source) {
|
||||
init();
|
||||
|
||||
var code = exports.compile(source);
|
||||
|
||||
// strip the function wrapper, we add our own.
|
||||
// TODO: this is very fragile
|
||||
code = code.split("\n").slice(1,-2).join("\n");
|
||||
|
||||
return eval(code);
|
||||
}
|
||||
|
||||
exports.make_narwhal_factory = function(path) {
|
||||
init();
|
||||
|
||||
var code = exports.compileFile(path);
|
||||
|
||||
// strip the function wrapper, we add our own.
|
||||
// TODO: this is very fragile
|
||||
code = code.split("\n").slice(1,-2).join("\n");
|
||||
|
||||
var factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
|
||||
|
||||
if (system.engine === "rhino")
|
||||
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
|
||||
|
||||
// eval requires parenthesis, but parenthesis break compileFunction.
|
||||
else
|
||||
return eval("(" + factoryText + ")");
|
||||
}
|
||||
|
||||
|
||||
var init = function() {
|
||||
// make sure it's only done once
|
||||
init = function(){}
|
||||
}
|
||||
23
lib-js/coffee-script/loader.js
Normal file
23
lib-js/coffee-script/loader.js
Normal file
@@ -0,0 +1,23 @@
|
||||
var coffeescript = null;
|
||||
|
||||
function CoffeeScriptLoader() {
|
||||
var loader = {};
|
||||
var factories = {};
|
||||
|
||||
loader.reload = function(topId, path) {
|
||||
if (!coffeescript) coffeescript = require("coffee-script");
|
||||
|
||||
//print("loading objective-j: " + topId + " (" + path + ")");
|
||||
factories[topId] = coffeescript.make_narwhal_factory(path);
|
||||
}
|
||||
|
||||
loader.load = function(topId, path) {
|
||||
if (!factories.hasOwnProperty(topId))
|
||||
loader.reload(topId, path);
|
||||
return factories[topId];
|
||||
}
|
||||
|
||||
return loader;
|
||||
};
|
||||
|
||||
require.loader.loaders.unshift([".cs", CoffeeScriptLoader()]);
|
||||
@@ -9,12 +9,12 @@ require "coffee_script/parse_error"
|
||||
# Namespace for all CoffeeScript internal classes.
|
||||
module CoffeeScript
|
||||
|
||||
VERSION = '0.1.0' # Keep in sync with the gemspec.
|
||||
VERSION = '0.1.2' # Keep in sync with the gemspec.
|
||||
|
||||
# Compile a script (String or IO) to JavaScript.
|
||||
def self.compile(script)
|
||||
def self.compile(script, options={})
|
||||
script = script.read if script.respond_to?(:read)
|
||||
Parser.new.parse(script).compile
|
||||
Parser.new.parse(script).compile(options)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(super|this)\b</string>
|
||||
<string>\b(super|this|extends)\b</string>
|
||||
<key>name</key>
|
||||
<string>variable.language.cs</string>
|
||||
</dict>
|
||||
|
||||
@@ -108,7 +108,7 @@ Usage:
|
||||
# Compile a single source file to JavaScript.
|
||||
def compile(script, source='')
|
||||
begin
|
||||
CoffeeScript.compile(script)
|
||||
CoffeeScript.compile(script, :no_wrap => @options[:no_wrap])
|
||||
rescue CoffeeScript::ParseError => e
|
||||
STDERR.puts e.message(source)
|
||||
exit(1) unless @options[:watch]
|
||||
@@ -147,7 +147,7 @@ Usage:
|
||||
opts.on('-l', '--lint', 'pipe the compiled JavaScript through JSLint') do |l|
|
||||
@options[:lint] = true
|
||||
end
|
||||
opts.on('-e', '--eval', 'eval a little scriptlet directly from the cli') do |e|
|
||||
opts.on('-e', '--eval', 'eval a little scriptlet or read from stdin') do |e|
|
||||
@options[:eval] = true
|
||||
end
|
||||
opts.on('-t', '--tokens', 'print the tokens that the lexer produces') do |t|
|
||||
@@ -156,6 +156,9 @@ Usage:
|
||||
opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
|
||||
ENV['VERBOSE'] = 'true'
|
||||
end
|
||||
opts.on('-n', '--no-wrap', 'suppress the top-level safety function wrapper') do |n|
|
||||
@options[:no_wrap] = true
|
||||
end
|
||||
opts.on_tail('--install-bundle', 'install the CoffeeScript TextMate bundle') do |i|
|
||||
install_bundle
|
||||
exit
|
||||
|
||||
@@ -10,8 +10,8 @@ token TRY CATCH FINALLY THROW
|
||||
token BREAK CONTINUE
|
||||
token FOR IN WHILE
|
||||
token SWITCH WHEN
|
||||
token SUPER
|
||||
token DELETE
|
||||
token DELETE INSTANCEOF TYPEOF
|
||||
token SUPER EXTENDS
|
||||
token NEWLINE
|
||||
token COMMENT
|
||||
token JS
|
||||
@@ -27,10 +27,10 @@ prechigh
|
||||
right '==' '!=' IS AINT
|
||||
left '&&' '||' AND OR
|
||||
right '-=' '+=' '/=' '*='
|
||||
right DELETE
|
||||
right DELETE INSTANCEOF TYPEOF
|
||||
left "."
|
||||
right THROW FOR IN WHILE NEW
|
||||
left UNLESS IF ELSE
|
||||
right THROW FOR IN WHILE NEW SUPER
|
||||
left UNLESS IF ELSE EXTENDS
|
||||
left ":" '||:' '&&:'
|
||||
right RETURN
|
||||
preclow
|
||||
@@ -81,6 +81,7 @@ rule
|
||||
| While
|
||||
| For
|
||||
| Switch
|
||||
| Extends
|
||||
| Comment
|
||||
;
|
||||
|
||||
@@ -185,6 +186,8 @@ rule
|
||||
| Expression '&&:' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
||||
|
||||
| DELETE Expression { result = OpNode.new(val[0], val[1]) }
|
||||
| TYPEOF Expression { result = OpNode.new(val[0], val[1]) }
|
||||
| Expression INSTANCEOF Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
||||
;
|
||||
|
||||
# Function definition.
|
||||
@@ -252,6 +255,11 @@ rule
|
||||
| Super { result = val[0] }
|
||||
;
|
||||
|
||||
# Extending an object's prototype.
|
||||
Extends:
|
||||
Value EXTENDS Expression { result = ExtendsNode.new(val[0], val[2]) }
|
||||
;
|
||||
|
||||
# A generic function invocation.
|
||||
Invocation:
|
||||
Value "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
|
||||
|
||||
@@ -14,8 +14,8 @@ module CoffeeScript
|
||||
"break", "continue",
|
||||
"for", "in", "while",
|
||||
"switch", "when",
|
||||
"super",
|
||||
"delete"]
|
||||
"super", "extends",
|
||||
"delete", "instanceof", "typeof"]
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER = /\A([a-zA-Z$_]\w*)/
|
||||
|
||||
@@ -75,16 +75,17 @@ module CoffeeScript
|
||||
end
|
||||
|
||||
# If this is the top-level Expressions, wrap everything in a safety closure.
|
||||
def root_compile
|
||||
code = compile(:indent => TAB, :scope => Scope.new)
|
||||
def root_compile(o={})
|
||||
indent = o[:no_wrap] ? '' : TAB
|
||||
code = compile(:indent => indent, :scope => Scope.new)
|
||||
code.gsub!(STRIP_TRAILING_WHITESPACE, '')
|
||||
"(function(){\n#{code}\n})();"
|
||||
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
|
||||
end
|
||||
|
||||
# The extra fancy is to handle pushing down returns and assignments
|
||||
# recursively to the final lines of inner statements.
|
||||
def compile(options={})
|
||||
return root_compile unless options[:scope]
|
||||
return root_compile(options) unless options[:scope]
|
||||
code = @expressions.map { |node|
|
||||
o = super(options)
|
||||
if last?(node) && (o[:return] || o[:assign])
|
||||
@@ -209,10 +210,25 @@ module CoffeeScript
|
||||
|
||||
def compile_super(args, o)
|
||||
methname = o[:last_assign].sub(LEADING_DOT, '')
|
||||
"this.constructor.prototype.#{methname}.call(this, #{args})"
|
||||
arg_part = args.empty? ? '' : ", #{args}"
|
||||
"#{o[:proto_assign]}.prototype.__proto__.#{methname}.call(this#{arg_part})"
|
||||
end
|
||||
end
|
||||
|
||||
# Node to extend an object's prototype with an ancestor object.
|
||||
class ExtendsNode < Node
|
||||
attr_reader :sub_object, :super_object
|
||||
|
||||
def initialize(sub_object, super_object)
|
||||
@sub_object, @super_object = sub_object, super_object
|
||||
end
|
||||
|
||||
def compile(o={})
|
||||
"#{@sub_object.compile(o)}.prototype.__proto__ = #{@super_object.compile(o)}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A value, indexed or dotted into, or vanilla.
|
||||
class ValueNode < Node
|
||||
attr_reader :literal, :properties, :last
|
||||
@@ -298,7 +314,8 @@ module CoffeeScript
|
||||
|
||||
# Setting the value of a local variable, or the value of an object property.
|
||||
class AssignNode < Node
|
||||
LEADING_VAR = /\Avar\s+/
|
||||
LEADING_VAR = /\Avar\s+/
|
||||
PROTO_ASSIGN = /\A(\S+)\.prototype/
|
||||
|
||||
statement
|
||||
custom_return
|
||||
@@ -315,9 +332,10 @@ module CoffeeScript
|
||||
|
||||
def compile(o={})
|
||||
o = super(o)
|
||||
name = @variable.respond_to?(:compile) ? @variable.compile(o) : @variable
|
||||
name = @variable.respond_to?(:compile) ? @variable.compile(o) : @variable.to_s
|
||||
last = @variable.respond_to?(:last) ? @variable.last.to_s : name.to_s
|
||||
o = o.merge(:assign => name, :last_assign => last)
|
||||
proto = name[PROTO_ASSIGN, 1]
|
||||
o = o.merge(:assign => name, :last_assign => last, :proto_assign => proto)
|
||||
postfix = o[:return] ? ";\n#{o[:indent]}return #{name}" : ''
|
||||
return write("#{@variable}: #{@value.compile(o)}") if @context == :object
|
||||
return write("#{name} = #{@value.compile(o)}#{postfix}") if @variable.properties? && !@value.custom_assign?
|
||||
@@ -342,7 +360,8 @@ module CoffeeScript
|
||||
"aint" => "!==",
|
||||
'not' => '!',
|
||||
}
|
||||
CONDITIONALS = ['||:', '&&:']
|
||||
CONDITIONALS = ['||:', '&&:']
|
||||
PREFIX_OPERATORS = ['typeof', 'delete']
|
||||
|
||||
attr_reader :operator, :first, :second
|
||||
|
||||
@@ -369,7 +388,7 @@ module CoffeeScript
|
||||
end
|
||||
|
||||
def compile_unary(o)
|
||||
space = @operator.to_s == 'delete' ? ' ' : ''
|
||||
space = PREFIX_OPERATORS.include?(@operator.to_s) ? ' ' : ''
|
||||
parts = [@operator.to_s, space, @first.compile(o)]
|
||||
parts.reverse! if @flip
|
||||
parts.join('')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
9
package.json
Normal file
9
package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "coffee-script",
|
||||
"lib": "lib-js",
|
||||
"preload": ["coffee-script/loader"],
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "0.1.2"
|
||||
}
|
||||
29
test/fixtures/each_no_wrap.js
vendored
Normal file
29
test/fixtures/each_no_wrap.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
// The cornerstone, an each implementation.
|
||||
// Handles objects implementing forEach, arrays, and raw objects.
|
||||
_.each = function(obj, iterator, context) {
|
||||
var index = 0;
|
||||
try {
|
||||
if (obj.forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (_.isArray(obj) || _.isArguments(obj)) {
|
||||
var a = obj;
|
||||
for (var b=0, c=a.length; b<c; b++) {
|
||||
var item = a[b];
|
||||
var i = b;
|
||||
iterator.call(context, item, i, obj);
|
||||
}
|
||||
} else {
|
||||
var d = _.keys(obj);
|
||||
for (var e=0, f=d.length; e<f; e++) {
|
||||
var key = d[e];
|
||||
iterator.call(context, obj[key], key, obj);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e !== breaker) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
23
test/fixtures/execution/calling_super.cs
vendored
Normal file
23
test/fixtures/execution/calling_super.cs
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Base: => .
|
||||
Base.prototype.func: string =>
|
||||
'zero/' + string.
|
||||
|
||||
FirstChild: => .
|
||||
FirstChild extends new Base()
|
||||
FirstChild.prototype.func: string =>
|
||||
super('one/') + string.
|
||||
|
||||
SecondChild: => .
|
||||
SecondChild extends new FirstChild()
|
||||
SecondChild.prototype.func: string =>
|
||||
super('two/') + string.
|
||||
|
||||
ThirdChild: => .
|
||||
ThirdChild extends new SecondChild()
|
||||
ThirdChild.prototype.func: string =>
|
||||
super('three/') + string.
|
||||
|
||||
result: (new ThirdChild()).func('four')
|
||||
|
||||
print(result is 'zero/one/two/three/four')
|
||||
|
||||
27
test/fixtures/execution/calling_super.js
vendored
Normal file
27
test/fixtures/execution/calling_super.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
(function(){
|
||||
var Base = function() {
|
||||
};
|
||||
Base.prototype.func = function(string) {
|
||||
return 'zero/' + string;
|
||||
};
|
||||
var FirstChild = function() {
|
||||
};
|
||||
FirstChild.prototype.__proto__ = new Base();
|
||||
FirstChild.prototype.func = function(string) {
|
||||
return FirstChild.prototype.__proto__.func.call(this, 'one/') + string;
|
||||
};
|
||||
var SecondChild = function() {
|
||||
};
|
||||
SecondChild.prototype.__proto__ = new FirstChild();
|
||||
SecondChild.prototype.func = function(string) {
|
||||
return SecondChild.prototype.__proto__.func.call(this, 'two/') + string;
|
||||
};
|
||||
var ThirdChild = function() {
|
||||
};
|
||||
ThirdChild.prototype.__proto__ = new SecondChild();
|
||||
ThirdChild.prototype.func = function(string) {
|
||||
return ThirdChild.prototype.__proto__.func.call(this, 'three/') + string;
|
||||
};
|
||||
var result = (new ThirdChild()).func('four');
|
||||
print(result === 'zero/one/two/three/four');
|
||||
})();
|
||||
10
test/fixtures/execution/keyword_operators.cs
vendored
Normal file
10
test/fixtures/execution/keyword_operators.cs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
a: 5
|
||||
atype: typeof a
|
||||
|
||||
b: "hello"
|
||||
btype: typeof b
|
||||
|
||||
Klass: => .
|
||||
k: new Klass()
|
||||
|
||||
print(atype is 'number' and btype is 'string' and k instanceof Klass)
|
||||
10
test/fixtures/execution/keyword_operators.js
vendored
Normal file
10
test/fixtures/execution/keyword_operators.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
(function(){
|
||||
var a = 5;
|
||||
var atype = typeof a;
|
||||
var b = "hello";
|
||||
var btype = typeof b;
|
||||
var Klass = function() {
|
||||
};
|
||||
var k = new Klass();
|
||||
print(atype === 'number' && btype === 'string' && k instanceof Klass);
|
||||
})();
|
||||
@@ -10,8 +10,9 @@ class ExecutionTest < Test::Unit::TestCase
|
||||
starting_place = File.expand_path(Dir.pwd)
|
||||
Dir.chdir('/Users/jashkenas/Desktop/Beauty/Code/v8')
|
||||
sources.each do |source|
|
||||
# puts `./shell #{source}`
|
||||
assert `./shell #{source}`.chomp.to_sym == :true
|
||||
suceeded = `./shell #{source}`.chomp.to_sym == :true
|
||||
puts "failed: #{source}" unless suceeded
|
||||
assert suceeded
|
||||
end
|
||||
ensure
|
||||
Dir.chdir(starting_place)
|
||||
|
||||
@@ -72,4 +72,9 @@ class ParserTest < Test::Unit::TestCase
|
||||
assert nodes.compile == File.read('test/fixtures/each.js')
|
||||
end
|
||||
|
||||
def test_no_wrap
|
||||
nodes = @par.parse(File.read('test/fixtures/each.cs'))
|
||||
assert nodes.compile(:no_wrap => true) == File.read('test/fixtures/each_no_wrap.js')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user