Putting 'constructor' back. Improving constructor definitions.

This commit is contained in:
Jeremy Ashkenas
2010-11-13 12:17:09 -05:00
parent 3059db8515
commit 354708dbc2
13 changed files with 120 additions and 98 deletions

View File

@@ -185,7 +185,7 @@
], ],
Object: [ Object: [
o('{ AssignList OptComma }', function() { o('{ AssignList OptComma }', function() {
return new Obj($2); return new Obj($2, $1.generated);
}) })
], ],
AssignList: [ AssignList: [

View File

@@ -369,9 +369,6 @@
Value.prototype.isArray = function() { Value.prototype.isArray = function() {
return !this.properties.length && this.base instanceof Arr; return !this.properties.length && this.base instanceof Arr;
}; };
Value.prototype.isObject = function() {
return !this.properties.length && this.base instanceof Obj;
};
Value.prototype.isComplex = function() { Value.prototype.isComplex = function() {
return this.hasProperties() || this.base.isComplex(); return this.hasProperties() || this.base.isComplex();
}; };
@@ -398,6 +395,12 @@
Value.prototype.assigns = function(name) { Value.prototype.assigns = function(name) {
return !this.properties.length && this.base.assigns(name); return !this.properties.length && this.base.assigns(name);
}; };
Value.prototype.isObject = function(onlyGenerated) {
if (this.properties.length) {
return false;
}
return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated);
};
Value.prototype.makeReturn = function() { Value.prototype.makeReturn = function() {
if (this.properties.length) { if (this.properties.length) {
return Value.__super__.makeReturn.call(this); return Value.__super__.makeReturn.call(this);
@@ -664,7 +667,8 @@
return Index; return Index;
}(); }();
exports.Obj = Obj = function() { exports.Obj = Obj = function() {
function Obj(props) { function Obj(props, _arg) {
this.generated = _arg != null ? _arg : false;
this.objects = this.properties = props || []; this.objects = this.properties = props || [];
} }
__extends(Obj, Base); __extends(Obj, Base);
@@ -821,6 +825,7 @@
Class.prototype.children = ['variable', 'parent', 'body']; Class.prototype.children = ['variable', 'parent', 'body'];
Class.prototype.compileNode = function(o) { Class.prototype.compileNode = function(o) {
var bname, boundFuncs, bvar, convert, ctor, decl, exps, i, klass, lname, name, node, others, tail, _fn, _i, _j, _len, _len2, _len3, _ref, _ref2; var bname, boundFuncs, bvar, convert, ctor, decl, exps, i, klass, lname, name, node, others, tail, _fn, _i, _j, _len, _len2, _len3, _ref, _ref2;
ctor = null;
if (this.variable) { if (this.variable) {
decl = (tail = last(this.variable.properties)) ? tail instanceof Accessor && tail.name.value : this.variable.base.value; decl = (tail = last(this.variable.properties)) ? tail instanceof Accessor && tail.name.value : this.variable.base.value;
decl && (decl = IDENTIFIER.test(decl) && decl); decl && (decl = IDENTIFIER.test(decl) && decl);
@@ -838,19 +843,33 @@
} }
}); });
convert = function(node) { convert = function(node) {
var assign, base, func, _i, _len, _ref, _results; var assign, base, func, props, _results;
_ref = node.base.properties; props = node.base.properties.slice(0);
_results = []; _results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { while (assign = props.shift()) {
assign = _ref[_i];
if (assign instanceof Assign) { if (assign instanceof Assign) {
base = assign.variable.base; base = assign.variable.base;
assign.variable = new Value(lname, [new Accessor(base, 'proto')]);
delete assign.context; delete assign.context;
func = assign.value; func = assign.value;
if (func instanceof Code && func.bound) { if (base.value === 'constructor') {
boundFuncs.push(base); if (ctor) {
func.bound = false; throw new Error('cannot define more than one constructor in a class');
}
if (func.bound) {
throw new Error('cannot define a constructor as a bound function');
}
if (func instanceof Code) {
ctor = func;
} else {
ctor = new Assign(new Value(lname), func);
}
assign = null;
} else {
assign.variable = new Value(lname, [new Accessor(base, 'proto')]);
if (func instanceof Code && func.bound) {
boundFuncs.push(base);
func.bound = false;
}
} }
} }
_results.push(assign); _results.push(assign);
@@ -862,18 +881,8 @@
_ref = exps = this.body.expressions; _ref = exps = this.body.expressions;
for (i = 0, _len = _ref.length; i < _len; i++) { for (i = 0, _len = _ref.length; i < _len; i++) {
node = _ref[i]; node = _ref[i];
if (node instanceof Value && node.isObject()) { if (node instanceof Value && node.isObject(true)) {
exps[i] = convert(node); exps[i] = compact(convert(node));
} else if (node instanceof Code) {
if (ctor) {
throw new Error('cannot define more than one constructor in a class');
}
if (node.bound) {
throw new Error('cannot define a constructor as a bound function');
}
ctor = node;
exps.splice(i, 1);
exps.unshift(ctor);
} else { } else {
others.push(node); others.push(node);
} }
@@ -885,8 +894,8 @@
_ref = n2.expressions; _ref = n2.expressions;
for (j = 0, _len = _ref.length; j < _len; j++) { for (j = 0, _len = _ref.length; j < _len; j++) {
expr2 = _ref[j]; expr2 = _ref[j];
if (expr2 instanceof Value && expr2.isObject()) { if (expr2 instanceof Value && expr2.isObject(true)) {
n2.expressions[j] = convert(expr2); n2.expressions[j] = compact(convert(expr2));
} }
} }
return n2.expressions = flatten(n2.expressions); return n2.expressions = flatten(n2.expressions);
@@ -899,7 +908,7 @@
} }
this.body.expressions = exps = flatten(exps); this.body.expressions = exps = flatten(exps);
if (!ctor) { if (!ctor) {
exps.unshift(ctor = new Code); ctor = new Code;
if (this.parent) { if (this.parent) {
ctor.body.push(new Call('super', [new Splat(new Literal('arguments'))])); ctor.body.push(new Call('super', [new Splat(new Literal('arguments'))]));
} }
@@ -908,8 +917,9 @@
ctor.klass = null; ctor.klass = null;
ctor.noReturn = true; ctor.noReturn = true;
if (this.parent) { if (this.parent) {
exps.splice(1, 0, new Extends(lname, this.parent)); exps.unshift(new Extends(lname, this.parent));
} }
exps.unshift(ctor);
exps.push(lname); exps.push(lname);
if (boundFuncs.length) { if (boundFuncs.length) {
for (_j = 0, _len3 = boundFuncs.length; _j < _len3; _j++) { for (_j = 0, _len3 = boundFuncs.length; _j < _len3; _j++) {

View File

@@ -181,7 +181,7 @@ case 84:this.$ = yy.extend($$[$0-2+2-1], {
proto: true proto: true
}); });
break; break;
case 85:this.$ = new yy.Obj($$[$0-4+2-1]); case 85:this.$ = new yy.Obj($$[$0-4+2-1], $$[$0-4+1-1].generated);
break; break;
case 86:this.$ = []; case 86:this.$ = [];
break; break;

View File

@@ -122,7 +122,7 @@
return this.tokens.splice(i, 0, ['}', '}', token[2]]); return this.tokens.splice(i, 0, ['}', '}', token[2]]);
}; };
return this.scanTokens(function(token, i, tokens) { return this.scanTokens(function(token, i, tokens) {
var ago1, ago2, idx, tag, tok, _ref, _ref2; var ago1, ago2, idx, tag, tok, value, _ref, _ref2;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) { if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]); stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]);
return 1; return 1;
@@ -139,7 +139,9 @@
if (this.tag(idx - 2) === 'HERECOMMENT') { if (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2; idx -= 2;
} }
tok = ['{', '{', token[2]]; value = new String('{');
value.generated = true;
tok = ['{', value, token[2]];
tok.generated = true; tok.generated = true;
tokens.splice(idx, 0, tok); tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action); this.detectEnd(i + 2, condition, action);

View File

@@ -258,7 +258,7 @@ grammar =
# In CoffeeScript, an object literal is simply a list of assignments. # In CoffeeScript, an object literal is simply a list of assignments.
Object: [ Object: [
o '{ AssignList OptComma }', -> new Obj $2 o '{ AssignList OptComma }', -> new Obj $2, $1.generated
] ]
# Assignment of properties within an object literal can be separated by # Assignment of properties within an object literal can be separated by

View File

@@ -157,7 +157,7 @@ exports.Expressions = class Expressions extends Base
children: ['expressions'] children: ['expressions']
(nodes) -> constructor: (nodes) ->
@expressions = compact flatten nodes or [] @expressions = compact flatten nodes or []
# Tack an expression on to the end of this expression list. # Tack an expression on to the end of this expression list.
@@ -257,7 +257,7 @@ exports.Expressions = class Expressions extends Base
# `true`, `false`, `null`... # `true`, `false`, `null`...
exports.Literal = class Literal extends Base exports.Literal = class Literal extends Base
(@value) -> constructor: (@value) ->
makeReturn: -> makeReturn: ->
if @isPureStatement() then this else new Return this if @isPureStatement() then this else new Return this
@@ -292,7 +292,7 @@ exports.Return = class Return extends Base
isStatement : YES isStatement : YES
isPureStatement: YES isPureStatement: YES
(@expression) -> constructor: (@expression) ->
makeReturn: THIS makeReturn: THIS
@@ -313,7 +313,7 @@ exports.Value = class Value extends Base
children: ['base', 'properties'] children: ['base', 'properties']
# A **Value** has a base and a list of property accesses. # A **Value** has a base and a list of property accesses.
(base, props, tag) -> constructor: (base, props, tag) ->
return base if not props and base instanceof Value return base if not props and base instanceof Value
@base = base @base = base
@properties = props or [] @properties = props or []
@@ -329,7 +329,6 @@ exports.Value = class Value extends Base
# Some boolean checks for the benefit of other nodes. # Some boolean checks for the benefit of other nodes.
isArray : -> not @properties.length and @base instanceof Arr isArray : -> not @properties.length and @base instanceof Arr
isObject : -> not @properties.length and @base instanceof Obj
isComplex : -> @hasProperties() or @base.isComplex() isComplex : -> @hasProperties() or @base.isComplex()
isAssignable : -> @hasProperties() or @base.isAssignable() isAssignable : -> @hasProperties() or @base.isAssignable()
isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value
@@ -341,6 +340,10 @@ exports.Value = class Value extends Base
isStatement : (o) -> not @properties.length and @base.isStatement o isStatement : (o) -> not @properties.length and @base.isStatement o
assigns : (name) -> not @properties.length and @base.assigns name assigns : (name) -> not @properties.length and @base.assigns name
isObject: (onlyGenerated) ->
return no if @properties.length
(@base instanceof Obj) and (not onlyGenerated or @base.generated)
makeReturn: -> makeReturn: ->
if @properties.length then super() else @base.makeReturn() if @properties.length then super() else @base.makeReturn()
@@ -401,7 +404,7 @@ exports.Value = class Value extends Base
# at the same position. # at the same position.
exports.Comment = class Comment extends Base exports.Comment = class Comment extends Base
(@comment) -> constructor: (@comment) ->
isPureStatement: YES isPureStatement: YES
isStatement: YES isStatement: YES
@@ -420,7 +423,7 @@ exports.Call = class Call extends Base
children: ['variable', 'args'] children: ['variable', 'args']
(variable, @args = [], @soak) -> constructor: (variable, @args = [], @soak) ->
@isNew = false @isNew = false
@isSuper = variable is 'super' @isSuper = variable is 'super'
@variable = if @isSuper then null else variable @variable = if @isSuper then null else variable
@@ -523,7 +526,7 @@ exports.Extends = class Extends extends Base
children: ['child', 'parent'] children: ['child', 'parent']
(@child, @parent) -> constructor: (@child, @parent) ->
# Hooks one constructor into another's prototype chain. # Hooks one constructor into another's prototype chain.
compile: (o) -> compile: (o) ->
@@ -538,7 +541,7 @@ exports.Accessor = class Accessor extends Base
children: ['name'] children: ['name']
(@name, tag) -> constructor: (@name, tag) ->
@proto = if tag is 'proto' then '.prototype' else '' @proto = if tag is 'proto' then '.prototype' else ''
@soak = tag is 'soak' @soak = tag is 'soak'
@@ -555,7 +558,7 @@ exports.Index = class Index extends Base
children: ['index'] children: ['index']
(@index) -> constructor: (@index) ->
compile: (o) -> compile: (o) ->
(if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]" (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"
@@ -570,7 +573,7 @@ exports.Obj = class Obj extends Base
children: ['properties'] children: ['properties']
(props) -> constructor: (props, @generated = false) ->
@objects = @properties = props or [] @objects = @properties = props or []
compileNode: (o) -> compileNode: (o) ->
@@ -634,7 +637,7 @@ exports.Arr = class Arr extends Base
children: ['objects'] children: ['objects']
(objs) -> constructor: (objs) ->
@objects = objs or [] @objects = objs or []
compileNode: (o) -> compileNode: (o) ->
@@ -661,12 +664,14 @@ exports.Class = class Class extends Base
# Initialize a **Class** with its name, an optional superclass, and a # Initialize a **Class** with its name, an optional superclass, and a
# list of prototype property assignments. # list of prototype property assignments.
(@variable, @parent, @body = new Expressions) -> constructor: (@variable, @parent, @body = new Expressions) ->
# Instead of generating the JavaScript string directly, we build up the # Instead of generating the JavaScript string directly, we build up the
# equivalent syntax tree and compile that, in pieces. You can see the # equivalent syntax tree and compile that, in pieces. You can see the
# constructor, property assignments, and inheritance getting built out below. # constructor, property assignments, and inheritance getting built out below.
compileNode: (o) -> compileNode: (o) ->
ctor = null
if @variable if @variable
decl = if tail = last @variable.properties decl = if tail = last @variable.properties
tail instanceof Accessor and tail.name.value tail instanceof Accessor and tail.name.value
@@ -684,30 +689,34 @@ exports.Class = class Class extends Base
node.context = name if node.bound node.context = name if node.bound
convert = (node) -> convert = (node) ->
for assign in node.base.properties props = node.base.properties.slice 0
while assign = props.shift()
if assign instanceof Assign if assign instanceof Assign
base = assign.variable.base base = assign.variable.base
assign.variable = new Value(lname, [new Accessor(base, 'proto')])
delete assign.context delete assign.context
func = assign.value func = assign.value
if func instanceof Code and func.bound if base.value is 'constructor'
boundFuncs.push base if ctor
func.bound = no throw new Error 'cannot define more than one constructor in a class'
if func.bound
throw new Error 'cannot define a constructor as a bound function'
if func instanceof Code
ctor = func
else
ctor = new Assign(new Value(lname), func)
assign = null
else
assign.variable = new Value(lname, [new Accessor(base, 'proto')])
if func instanceof Code and func.bound
boundFuncs.push base
func.bound = no
assign assign
boundFuncs = [] boundFuncs = []
others = [] others = []
for node, i in exps = @body.expressions for node, i in exps = @body.expressions
if node instanceof Value and node.isObject() if node instanceof Value and node.isObject(true)
exps[i] = convert node exps[i] = compact convert node
else if node instanceof Code
if ctor
throw new Error 'cannot define more than one constructor in a class'
if node.bound
throw new Error 'cannot define a constructor as a bound function'
ctor = node
exps.splice(i, 1)
exps.unshift ctor
else else
others.push node others.push node
@@ -716,19 +725,20 @@ exports.Class = class Class extends Base
other.traverseChildren false, (n2) -> other.traverseChildren false, (n2) ->
if n2 instanceof Expressions if n2 instanceof Expressions
for expr2, j in n2.expressions for expr2, j in n2.expressions
if expr2 instanceof Value and expr2.isObject() if expr2 instanceof Value and expr2.isObject(true)
n2.expressions[j] = convert expr2 n2.expressions[j] = compact convert expr2
n2.expressions = flatten n2.expressions n2.expressions = flatten n2.expressions
@body.expressions = exps = flatten exps @body.expressions = exps = flatten exps
unless ctor unless ctor
exps.unshift ctor = new Code ctor = new Code
if @parent if @parent
ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] ctor.body.push new Call 'super', [new Splat new Literal 'arguments']
ctor.ctor = ctor.name = name ctor.ctor = ctor.name = name
ctor.klass = null ctor.klass = null
ctor.noReturn = yes ctor.noReturn = yes
exps.splice 1, 0, new Extends lname, @parent if @parent exps.unshift new Extends lname, @parent if @parent
exps.unshift ctor
exps.push lname exps.push lname
if boundFuncs.length if boundFuncs.length
@@ -752,7 +762,7 @@ exports.Assign = class Assign extends Base
children: ['variable', 'value'] children: ['variable', 'value']
(@variable, @value, @context) -> constructor: (@variable, @value, @context) ->
assigns: (name) -> assigns: (name) ->
@[if @context is 'object' then 'value' else 'variable'].assigns name @[if @context is 'object' then 'value' else 'variable'].assigns name
@@ -867,7 +877,7 @@ exports.Code = class Code extends Base
children: ['params', 'body'] children: ['params', 'body']
(params, body, tag) -> constructor: (params, body, tag) ->
@params = params or [] @params = params or []
@body = body or new Expressions @body = body or new Expressions
@bound = tag is 'boundfunc' @bound = tag is 'boundfunc'
@@ -934,7 +944,7 @@ exports.Param = class Param extends Base
children: ['name', 'value'] children: ['name', 'value']
(@name, @value, @splat) -> constructor: (@name, @value, @splat) ->
compile: (o) -> compile: (o) ->
@name.compile o, LEVEL_LIST @name.compile o, LEVEL_LIST
@@ -959,7 +969,7 @@ exports.Splat = class Splat extends Base
isAssignable: YES isAssignable: YES
(name) -> constructor: (name) ->
@name = if name.compile then name else new Literal name @name = if name.compile then name else new Literal name
assigns: (name) -> assigns: (name) ->
@@ -999,7 +1009,7 @@ exports.While = class While extends Base
isStatement: YES isStatement: YES
(condition, options) -> constructor: (condition, options) ->
@condition = if options?.invert then condition.invert() else condition @condition = if options?.invert then condition.invert() else condition
@guard = options?.guard @guard = options?.guard
@@ -1063,7 +1073,7 @@ exports.Op = class Op extends Base
children: ['first', 'second'] children: ['first', 'second']
(op, first, second, flip) -> constructor: (op, first, second, flip) ->
return new In first, second if op is 'in' return new In first, second if op is 'in'
if op is 'new' if op is 'new'
return first.newInstance() if first instanceof Call return first.newInstance() if first instanceof Call
@@ -1140,7 +1150,7 @@ exports.In = class In extends Base
invert: NEGATE invert: NEGATE
(@object, @array) -> constructor: (@object, @array) ->
compileNode: (o) -> compileNode: (o) ->
if @array instanceof Value and @array.isArray() if @array instanceof Value and @array.isArray()
@@ -1176,7 +1186,7 @@ exports.Try = class Try extends Base
isStatement: YES isStatement: YES
(@attempt, @error, @recovery, @ensure) -> constructor: (@attempt, @error, @recovery, @ensure) ->
makeReturn: -> makeReturn: ->
@attempt = @attempt .makeReturn() if @attempt @attempt = @attempt .makeReturn() if @attempt
@@ -1207,7 +1217,7 @@ exports.Throw = class Throw extends Base
isStatement: YES isStatement: YES
(@expression) -> constructor: (@expression) ->
# A **Throw** is already a return, of sorts... # A **Throw** is already a return, of sorts...
makeReturn: THIS makeReturn: THIS
@@ -1226,7 +1236,7 @@ exports.Existence = class Existence extends Base
invert: NEGATE invert: NEGATE
(@expression) -> constructor: (@expression) ->
compileNode: (o) -> compileNode: (o) ->
code = @expression.compile o, LEVEL_OP code = @expression.compile o, LEVEL_OP
@@ -1251,7 +1261,7 @@ exports.Parens = class Parens extends Base
children: ['expression'] children: ['expression']
(@expression) -> constructor: (@expression) ->
unwrap : -> @expression unwrap : -> @expression
isComplex : -> @expression.isComplex() isComplex : -> @expression.isComplex()
@@ -1281,7 +1291,7 @@ exports.For = class For extends Base
isStatement: YES isStatement: YES
(body, head) -> constructor: (body, head) ->
if head.index instanceof Value if head.index instanceof Value
throw SyntaxError 'index cannot be a pattern matching expression' throw SyntaxError 'index cannot be a pattern matching expression'
extend this, head extend this, head
@@ -1415,7 +1425,7 @@ exports.Switch = class Switch extends Base
isStatement: YES isStatement: YES
(@subject, @cases, @otherwise) -> constructor: (@subject, @cases, @otherwise) ->
makeReturn: -> makeReturn: ->
pair[1].makeReturn() for pair in @cases pair[1].makeReturn() for pair in @cases
@@ -1449,7 +1459,7 @@ exports.If = class If extends Base
children: ['condition', 'body', 'elseBody'] children: ['condition', 'body', 'elseBody']
(condition, @body, options = {}) -> constructor: (condition, @body, options = {}) ->
@condition = if options.invert then condition.invert() else condition @condition = if options.invert then condition.invert() else condition
@elseBody = null @elseBody = null
@isChain = false @isChain = false

View File

@@ -13,7 +13,7 @@ exports.OptionParser = class OptionParser
# [short-flag, long-flag, description] # [short-flag, long-flag, description]
# #
# Along with an an optional banner for the usage help. # Along with an an optional banner for the usage help.
(rules, @banner) -> constructor: (rules, @banner) ->
@rules = buildRules rules @rules = buildRules rules
# Parse the list of arguments, populating an `options` object with all of the # Parse the list of arguments, populating an `options` object with all of the

View File

@@ -123,7 +123,9 @@ class exports.Rewriter
else else
i - 1 i - 1
idx -= 2 if @tag(idx - 2) is 'HERECOMMENT' idx -= 2 if @tag(idx - 2) is 'HERECOMMENT'
tok = ['{', '{', token[2]] value = new String('{')
value.generated = yes
tok = ['{', value, token[2]]
tok.generated = yes tok.generated = yes
tokens.splice idx, 0, tok tokens.splice idx, 0, tok
@detectEnd i + 2, condition, action @detectEnd i + 2, condition, action

View File

@@ -17,7 +17,7 @@ exports.Scope = class Scope
# as well as a reference to the **Expressions** node is belongs to, which is # as well as a reference to the **Expressions** node is belongs to, which is
# where it should declare its variables, and a reference to the function that # where it should declare its variables, and a reference to the function that
# it wraps. # it wraps.
(@parent, @expressions, @method) -> constructor: (@parent, @expressions, @method) ->
@variables = [{name: 'arguments', type: 'arguments'}] @variables = [{name: 'arguments', type: 'arguments'}]
@positions = {} @positions = {}
if @parent if @parent

View File

@@ -35,7 +35,7 @@ eq context.arg, 3
eq context.arg.join(' '), '1 2 3' eq context.arg.join(' '), '1 2 3'
class Klass class Klass
(@one, @two) -> constructor: (@one, @two) ->
obj = new Klass 1, 2 obj = new Klass 1, 2

View File

@@ -18,7 +18,7 @@ thirdCtor = ->
@array = [1, 2, 3] @array = [1, 2, 3]
class ThirdChild extends SecondChild class ThirdChild extends SecondChild
-> thirdCtor.call this constructor: -> thirdCtor.call this
# Gratuitous comment for testing. # Gratuitous comment for testing.
func: (string) -> func: (string) ->
@@ -40,15 +40,15 @@ ok (new ThirdChild).array.join(' ') is '1 2 3'
class TopClass class TopClass
(arg) -> constructor: (arg) ->
@prop = 'top-' + arg @prop = 'top-' + arg
class SuperClass extends TopClass class SuperClass extends TopClass
(arg) -> constructor: (arg) ->
super 'super-' + arg super 'super-' + arg
class SubClass extends SuperClass class SubClass extends SuperClass
-> constructor: ->
super 'sub' super 'sub'
ok (new SubClass).prop is 'top-super-sub' ok (new SubClass).prop is 'top-super-sub'
@@ -57,7 +57,7 @@ ok (new SubClass).prop is 'top-super-sub'
class OneClass class OneClass
@new = 'new' @new = 'new'
function: 'function' function: 'function'
(name) -> @name = name constructor: (name) -> @name = name
class TwoClass extends OneClass class TwoClass extends OneClass
delete TwoClass.new delete TwoClass.new
@@ -131,10 +131,10 @@ ok obj.amI()
# super() calls in constructors of classes that are defined as object properties. # super() calls in constructors of classes that are defined as object properties.
class Hive class Hive
(name) -> @name = name constructor: (name) -> @name = name
class Hive.Bee extends Hive class Hive.Bee extends Hive
(name) -> super constructor: (name) -> super
maya = new Hive.Bee 'Maya' maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya' ok maya.name is 'Maya'
@@ -154,7 +154,7 @@ ok instance.name() is 'class'
# ... or statically, to the class. # ... or statically, to the class.
class Dog class Dog
(name) -> constructor: (name) ->
@name = name @name = name
bark: => bark: =>
@@ -188,7 +188,7 @@ eq (func() for func in m.generate()).join(' '), '10 10 10'
# Testing a contructor called with varargs. # Testing a contructor called with varargs.
class Connection class Connection
(one, two, three) -> constructor: (one, two, three) ->
[@one, @two, @three] = [one, two, three] [@one, @two, @three] = [one, two, three]
out: -> out: ->
@@ -281,12 +281,10 @@ classMaker = ->
@value = inner @value = inner
class One class One
ctor = classMaker() constructor: classMaker()
-> return new ctor
class Two class Two
ctor = classMaker() constructor: classMaker()
-> return new ctor
ok (new One).value is 1 ok (new One).value is 1
ok (new Two).value is 2 ok (new Two).value is 2

View File

@@ -146,7 +146,7 @@ ok expr(2, 4, 8).join(' ') is '4 16 64'
# Fast object comprehensions over all properties, including prototypal ones. # Fast object comprehensions over all properties, including prototypal ones.
class Cat class Cat
-> @name = 'Whiskers' constructor: -> @name = 'Whiskers'
breed: 'tabby' breed: 'tabby'
hair: 'cream' hair: 'cream'

View File

@@ -81,7 +81,7 @@ eq ident(non?.existent().method()), undefined, 'soaks inner values'
# Soaks constructor invocations. # Soaks constructor invocations.
a = 0 a = 0
class Foo class Foo
-> a += 1 constructor: -> a += 1
bar: "bat" bar: "bat"
ok (new Foo())?.bar is 'bat' ok (new Foo())?.bar is 'bat'