Compare commits

..

16 Commits
0.1.0 ... 0.1.2

Author SHA1 Message Date
Jeremy Ashkenas
9dc932e380 bumping to 0.1.2 to get the super()/extends fix out there 2009-12-24 17:05:55 -08:00
Jeremy Ashkenas
a71de4b5b6 got extends back in the language -- use it together with super 2009-12-24 16:49:23 -08:00
Jeremy Ashkenas
ada8dfc6d4 fixing super() calls, thanks to tolmasky 2009-12-24 16:23:23 -08:00
Jeremy Ashkenas
4112595368 removing the special-case std-reading in favor of '--eval' 2009-12-24 15:49:42 -08:00
Jeremy Ashkenas
c281db7730 document that -e can read from stdin 2009-12-24 15:35:58 -08:00
Jeremy Ashkenas
5e6b49ad1e with a working -n --no-wrap option to disable the top-level function safety wrapper 2009-12-24 15:31:00 -08:00
Jeremy Ashkenas
ec1a527575 Merge branch 'master' of git://github.com/tlrobinson/coffee-script 2009-12-24 15:05:56 -08:00
tlrobinson
dc0ab1afca Command line CoffeeScript 2009-12-24 14:42:57 -08:00
tlrobinson
ae72fbfd0d Narwhal support for CoffeeScript 2009-12-24 14:41:35 -08:00
tlrobinson
ad0735f765 Read from stdin if source is "-" 2009-12-24 14:40:39 -08:00
Jeremy Ashkenas
d49c178f1d added and -> &&, or -> || to the docs (they were missing) 2009-12-24 14:37:30 -08:00
Jeremy Ashkenas
8f8ba255b3 docs for 0.1.1 2009-12-24 12:02:28 -08:00
Jeremy Ashkenas
a4bc24817d bumping to 0.1.1 2009-12-24 11:59:19 -08:00
Jeremy Ashkenas
9eeac9b272 added the typeof operater as an OpNode 2009-12-24 11:50:44 -08:00
Jeremy Ashkenas
f859eb6cec added the instanceof operator to the grammar as an operation node 2009-12-24 11:46:51 -08:00
Jeremy Ashkenas
b29afc2c09 another wish 2009-12-24 10:31:44 -08:00
24 changed files with 1501 additions and 1113 deletions

3
bin/cs Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env narwhal
require("coffee-script").run(system.args);

View File

@@ -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']

View File

@@ -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).

View File

@@ -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>&amp;&amp;</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>

View File

@@ -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");

View File

@@ -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).

View File

@@ -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>&amp;&amp;</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">&quot;</span> moved <span class="String">&quot;</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">&quot;</span>m.<span class="String">&quot;</span></span>).
<span class="FunctionName">Snake</span><span class="Keyword">:</span> <span class="FunctionArgument">name</span> <span class="Storage">=&gt;</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">=&gt;</span>
alert(<span class="String"><span class="String">&quot;</span>Slithering...<span class="String">&quot;</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">=&gt;</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">=&gt;</span>
alert(<span class="String"><span class="String">&quot;</span>Galloping...<span class="String">&quot;</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">&quot;</span>Slithering...<span class="String">&quot;</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">&quot;</span>Galloping...<span class="String">&quot;</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">&quot;</span>Sammy the Python<span class="String">&quot;</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">&quot;</span>Tommy the Palomino<span class="String">&quot;</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
View 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(){}
}

View 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()]);

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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]) }

View File

@@ -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*)/

View File

@@ -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
View 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
View 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;
};

View 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')

View 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');
})();

View 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)

View 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);
})();

View File

@@ -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)

View File

@@ -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