mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
got extends back in the language -- use it together with super
This commit is contained in:
parent
47812d9ea6
commit
1c83e68292
10 changed files with 62 additions and 38 deletions
|
@ -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 />
|
||||
|
@ -332,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:
|
||||
|
@ -341,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>
|
||||
|
|
|
@ -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).
|
||||
|
|
34
index.html
34
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 />
|
||||
|
@ -565,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:
|
||||
|
@ -574,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>
|
||||
|
@ -585,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>).
|
||||
|
@ -614,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>);
|
||||
|
@ -641,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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -11,7 +11,7 @@ token BREAK CONTINUE
|
|||
token FOR IN WHILE
|
||||
token SWITCH WHEN
|
||||
token DELETE INSTANCEOF TYPEOF
|
||||
token SUPER
|
||||
token SUPER EXTENDS
|
||||
token NEWLINE
|
||||
token COMMENT
|
||||
token JS
|
||||
|
@ -29,8 +29,8 @@ prechigh
|
|||
right '-=' '+=' '/=' '*='
|
||||
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
|
||||
;
|
||||
|
||||
|
@ -254,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,7 +14,7 @@ module CoffeeScript
|
|||
"break", "continue",
|
||||
"for", "in", "while",
|
||||
"switch", "when",
|
||||
"super",
|
||||
"super", "extends",
|
||||
"delete", "instanceof", "typeof"]
|
||||
|
||||
# Token matching regexes.
|
||||
|
|
|
@ -215,6 +215,20 @@ module CoffeeScript
|
|||
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
|
||||
|
|
6
test/fixtures/execution/calling_super.cs
vendored
6
test/fixtures/execution/calling_super.cs
vendored
|
@ -3,17 +3,17 @@ Base.prototype.func: string =>
|
|||
'zero/' + string.
|
||||
|
||||
FirstChild: => .
|
||||
FirstChild.prototype.__proto__: new Base()
|
||||
FirstChild extends new Base()
|
||||
FirstChild.prototype.func: string =>
|
||||
super('one/') + string.
|
||||
|
||||
SecondChild: => .
|
||||
SecondChild.prototype.__proto__: new FirstChild()
|
||||
SecondChild extends new FirstChild()
|
||||
SecondChild.prototype.func: string =>
|
||||
super('two/') + string.
|
||||
|
||||
ThirdChild: => .
|
||||
ThirdChild.prototype.__proto__: new SecondChild()
|
||||
ThirdChild extends new SecondChild()
|
||||
ThirdChild.prototype.func: string =>
|
||||
super('three/') + string.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue