Permalink
...
Comparing changes
Open a pull request
- 12 commits
- 22 files changed
- 0 commit comments
- 2 contributors
Unified
Split
Showing
with
1,307 additions
and 986 deletions.
- +3 −0 bin/cs
- +1 −1 coffee-script.gemspec
- +2 −2 documentation/cs/super.cs
- +30 −7 documentation/index.html.erb
- +4 −4 documentation/js/super.js
- +2 −2 examples/code.cs
- +40 −17 index.html
- +91 −0 lib-js/coffee-script.js
- +23 −0 lib-js/coffee-script/loader.js
- +3 −3 lib/coffee-script.rb
- +1 −1 lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
- +5 −2 lib/coffee_script/command_line.rb
- +9 −3 lib/coffee_script/grammar.y
- +1 −1 lib/coffee_script/lexer.rb
- +26 −8 lib/coffee_script/nodes.rb
- +970 −933 lib/coffee_script/parser.rb
- +9 −0 package.json
- +29 −0 test/fixtures/each_no_wrap.js
- +23 −0 test/fixtures/execution/calling_super.cs
- +27 −0 test/fixtures/execution/calling_super.js
- +3 −2 test/unit/test_execution.rb
- +5 −0 test/unit/test_parser.rb
View
3
bin/cs
| @@ -0,0 +1,3 @@ | ||
| +#!/usr/bin/env narwhal | ||
| + | ||
| +require("coffee-script").run(system.args); |
View
2
coffee-script.gemspec
| @@ -1,6 +1,6 @@ | ||
| Gem::Specification.new do |s| | ||
| s.name = 'coffee-script' | ||
| - s.version = '0.1.1' # 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/" | ||
View
4
documentation/cs/super.cs
| @@ -3,13 +3,13 @@ | ||
| 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
37
documentation/index.html.erb
| @@ -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 /> | ||
| @@ -284,6 +284,10 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre> | ||
| 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>, | ||
| <b>if</b>/<b>else</b>, and <b>switch</b>/<b>when</b> statements. | ||
| @@ -328,18 +332,20 @@ 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: | ||
| <a href="http://code.google.com/p/base2/">Base2</a>, | ||
| <a href="http://prototypejs.org/">Prototype.js</a>, | ||
| <a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc. | ||
| 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> | ||
| @@ -415,7 +421,24 @@ coffee-script --print app/scripts/*.cs > concatenation.js</pre> | ||
| <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
8
documentation/js/super.js
| @@ -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
4
examples/code.cs
| @@ -145,13 +145,13 @@ | ||
| 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
57
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 /> | ||
| @@ -459,6 +459,10 @@ <h2 id="installation">Installation and Usage</h2> | ||
| 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>, | ||
| <b>if</b>/<b>else</b>, and <b>switch</b>/<b>when</b> statements. | ||
| @@ -561,18 +565,20 @@ <h2 id="installation">Installation and Usage</h2> | ||
| 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: | ||
| <a href="http://code.google.com/p/base2/">Base2</a>, | ||
| <a href="http://prototypejs.org/">Prototype.js</a>, | ||
| <a href="http://jsclass.jcoglan.com/">JS.Class</a>, etc. | ||
| 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 @@ <h2 id="installation">Installation and Usage</h2> | ||
| 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 @@ <h2 id="installation">Installation and Usage</h2> | ||
| <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 @@ <h2 id="installation">Installation and Usage</h2> | ||
| 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"); | ||
| @@ -794,7 +800,24 @@ <h2 id="contributing">Contributing</h2> | ||
| <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
91
lib-js/coffee-script.js
| @@ -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
23
lib-js/coffee-script/loader.js
| @@ -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()]); |
Oops, something went wrong.