1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Back to naked constructors.

This commit is contained in:
Jeremy Ashkenas 2010-11-13 15:22:18 -05:00
parent f0b73dc9f5
commit 2aedbc2e42
12 changed files with 74 additions and 82 deletions

View file

@ -1,5 +1,5 @@
class Animal class Animal
constructor: (@name) -> (@name) ->
move: (meters) -> move: (meters) ->
alert @name + " moved " + meters + "m." alert @name + " moved " + meters + "m."

View file

@ -135,7 +135,7 @@ aliquam erat volutpat. Ut wisi enim ad."
# Inheritance and calling super. # Inheritance and calling super.
class Animal class Animal
constructor: (@name) -> (@name) ->
move: (meters) -> move: (meters) ->
alert this.name + " moved " + meters + "m." alert this.name + " moved " + meters + "m."

View file

@ -1,7 +1,7 @@
# "Classic" linked list implementation that doesn't keep track of its size. # "Classic" linked list implementation that doesn't keep track of its size.
class LinkedList class LinkedList
constructor: -> ->
this._head = null # Pointer to the first item in the list. this._head = null # Pointer to the first item in the list.

View file

@ -71,7 +71,7 @@ print p.name
# Policeman ('Constable') print # Policeman ('Constable') print
class Policeman extends Person class Policeman extends Person
constructor: (@rank) -> (@rank) ->
print: -> print: ->
print 'My name is ' + @name + " and I'm a " + @rank + '.' print 'My name is ' + @name + " and I'm a " + @rank + '.'

View file

@ -851,25 +851,10 @@
base = assign.variable.base; base = assign.variable.base;
delete assign.context; delete assign.context;
func = assign.value; func = assign.value;
if (base.value === 'constructor') { assign.variable = new Value(lname, [new Accessor(base, 'proto')]);
if (ctor) { if (func instanceof Code && func.bound) {
throw new Error('cannot define more than one constructor in a class'); boundFuncs.push(base);
} func.bound = false;
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);
@ -883,6 +868,15 @@
node = _ref[i]; node = _ref[i];
if (node instanceof Value && node.isObject(true)) { if (node instanceof Value && node.isObject(true)) {
exps[i] = compact(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[i] = null;
} else { } else {
others.push(node); others.push(node);
} }
@ -906,7 +900,7 @@
other = others[_i]; other = others[_i];
_fn(other); _fn(other);
} }
this.body.expressions = exps = flatten(exps); this.body.expressions = exps = compact(flatten(exps));
if (!ctor) { if (!ctor) {
ctor = new Code; ctor = new Code;
if (this.parent) { if (this.parent) {

View file

@ -157,7 +157,7 @@ exports.Expressions = class Expressions extends Base
children: ['expressions'] children: ['expressions']
constructor: (nodes) -> (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
constructor: (@value) -> (@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
constructor: (@expression) -> (@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.
constructor: (base, props, tag) -> (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 []
@ -404,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
constructor: (@comment) -> (@comment) ->
isPureStatement: YES isPureStatement: YES
isStatement: YES isStatement: YES
@ -423,7 +423,7 @@ exports.Call = class Call extends Base
children: ['variable', 'args'] children: ['variable', 'args']
constructor: (variable, @args = [], @soak) -> (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
@ -526,7 +526,7 @@ exports.Extends = class Extends extends Base
children: ['child', 'parent'] children: ['child', 'parent']
constructor: (@child, @parent) -> (@child, @parent) ->
# Hooks one constructor into another's prototype chain. # Hooks one constructor into another's prototype chain.
compile: (o) -> compile: (o) ->
@ -541,7 +541,7 @@ exports.Accessor = class Accessor extends Base
children: ['name'] children: ['name']
constructor: (@name, tag) -> (@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'
@ -558,7 +558,7 @@ exports.Index = class Index extends Base
children: ['index'] children: ['index']
constructor: (@index) -> (@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 }]"
@ -573,7 +573,7 @@ exports.Obj = class Obj extends Base
children: ['properties'] children: ['properties']
constructor: (props, @generated = false) -> (props, @generated = false) ->
@objects = @properties = props or [] @objects = @properties = props or []
compileNode: (o) -> compileNode: (o) ->
@ -637,7 +637,7 @@ exports.Arr = class Arr extends Base
children: ['objects'] children: ['objects']
constructor: (objs) -> (objs) ->
@objects = objs or [] @objects = objs or []
compileNode: (o) -> compileNode: (o) ->
@ -664,7 +664,7 @@ 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.
constructor: (@variable, @parent, @body = new Expressions) -> (@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
@ -695,21 +695,10 @@ exports.Class = class Class extends Base
base = assign.variable.base base = assign.variable.base
delete assign.context delete assign.context
func = assign.value func = assign.value
if base.value is 'constructor' assign.variable = new Value(lname, [new Accessor(base, 'proto')])
if ctor if func instanceof Code and func.bound
throw new Error 'cannot define more than one constructor in a class' boundFuncs.push base
if func.bound func.bound = no
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 = []
@ -717,6 +706,13 @@ exports.Class = class Class extends Base
for node, i in exps = @body.expressions for node, i in exps = @body.expressions
if node instanceof Value and node.isObject(true) if node instanceof Value and node.isObject(true)
exps[i] = compact 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[i] = null
else else
others.push node others.push node
@ -729,7 +725,7 @@ exports.Class = class Class extends Base
n2.expressions[j] = compact 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 = compact flatten exps
unless ctor unless ctor
ctor = new Code ctor = new Code
if @parent if @parent
@ -762,7 +758,7 @@ exports.Assign = class Assign extends Base
children: ['variable', 'value'] children: ['variable', 'value']
constructor: (@variable, @value, @context) -> (@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
@ -877,7 +873,7 @@ exports.Code = class Code extends Base
children: ['params', 'body'] children: ['params', 'body']
constructor: (params, body, tag) -> (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'
@ -944,7 +940,7 @@ exports.Param = class Param extends Base
children: ['name', 'value'] children: ['name', 'value']
constructor: (@name, @value, @splat) -> (@name, @value, @splat) ->
compile: (o) -> compile: (o) ->
@name.compile o, LEVEL_LIST @name.compile o, LEVEL_LIST
@ -969,7 +965,7 @@ exports.Splat = class Splat extends Base
isAssignable: YES isAssignable: YES
constructor: (name) -> (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) ->
@ -1009,7 +1005,7 @@ exports.While = class While extends Base
isStatement: YES isStatement: YES
constructor: (condition, options) -> (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
@ -1073,7 +1069,7 @@ exports.Op = class Op extends Base
children: ['first', 'second'] children: ['first', 'second']
constructor: (op, first, second, flip) -> (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
@ -1150,7 +1146,7 @@ exports.In = class In extends Base
invert: NEGATE invert: NEGATE
constructor: (@object, @array) -> (@object, @array) ->
compileNode: (o) -> compileNode: (o) ->
if @array instanceof Value and @array.isArray() if @array instanceof Value and @array.isArray()
@ -1186,7 +1182,7 @@ exports.Try = class Try extends Base
isStatement: YES isStatement: YES
constructor: (@attempt, @error, @recovery, @ensure) -> (@attempt, @error, @recovery, @ensure) ->
makeReturn: -> makeReturn: ->
@attempt = @attempt .makeReturn() if @attempt @attempt = @attempt .makeReturn() if @attempt
@ -1217,7 +1213,7 @@ exports.Throw = class Throw extends Base
isStatement: YES isStatement: YES
constructor: (@expression) -> (@expression) ->
# A **Throw** is already a return, of sorts... # A **Throw** is already a return, of sorts...
makeReturn: THIS makeReturn: THIS
@ -1236,7 +1232,7 @@ exports.Existence = class Existence extends Base
invert: NEGATE invert: NEGATE
constructor: (@expression) -> (@expression) ->
compileNode: (o) -> compileNode: (o) ->
code = @expression.compile o, LEVEL_OP code = @expression.compile o, LEVEL_OP
@ -1261,7 +1257,7 @@ exports.Parens = class Parens extends Base
children: ['expression'] children: ['expression']
constructor: (@expression) -> (@expression) ->
unwrap : -> @expression unwrap : -> @expression
isComplex : -> @expression.isComplex() isComplex : -> @expression.isComplex()
@ -1291,7 +1287,7 @@ exports.For = class For extends Base
isStatement: YES isStatement: YES
constructor: (body, head) -> (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
@ -1425,7 +1421,7 @@ exports.Switch = class Switch extends Base
isStatement: YES isStatement: YES
constructor: (@subject, @cases, @otherwise) -> (@subject, @cases, @otherwise) ->
makeReturn: -> makeReturn: ->
pair[1].makeReturn() for pair in @cases pair[1].makeReturn() for pair in @cases
@ -1459,7 +1455,7 @@ exports.If = class If extends Base
children: ['condition', 'body', 'elseBody'] children: ['condition', 'body', 'elseBody']
constructor: (condition, @body, options = {}) -> (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.
constructor: (rules, @banner) -> (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

@ -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.
constructor: (@parent, @expressions, @method) -> (@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
constructor: (@one, @two) -> (@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
constructor: -> thirdCtor.call this -> 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
constructor: (arg) -> (arg) ->
@prop = 'top-' + arg @prop = 'top-' + arg
class SuperClass extends TopClass class SuperClass extends TopClass
constructor: (arg) -> (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'
constructor: (name) -> @name = name (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
constructor: (name) -> @name = name (name) -> @name = name
class Hive.Bee extends Hive class Hive.Bee extends Hive
constructor: (name) -> super (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
constructor: (name) -> (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
constructor: (one, two, three) -> (one, two, three) ->
[@one, @two, @three] = [one, two, three] [@one, @two, @three] = [one, two, three]
out: -> out: ->
@ -281,10 +281,12 @@ classMaker = ->
@value = inner @value = inner
class One class One
constructor: classMaker() ctor = classMaker()
-> ctor.call this
class Two class Two
constructor: classMaker() ctor = classMaker()
-> ctor.call this
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
constructor: -> @name = 'Whiskers' -> @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
constructor: -> a += 1 -> a += 1
bar: "bat" bar: "bat"
ok (new Foo())?.bar is 'bat' ok (new Foo())?.bar is 'bat'