diff --git a/documentation/coffee/classes.coffee b/documentation/coffee/classes.coffee index 6794518a..7175baf1 100644 --- a/documentation/coffee/classes.coffee +++ b/documentation/coffee/classes.coffee @@ -1,5 +1,5 @@ class Animal - constructor: (@name) -> + (@name) -> move: (meters) -> alert @name + " moved " + meters + "m." diff --git a/examples/code.coffee b/examples/code.coffee index b8b18124..88e8daae 100644 --- a/examples/code.coffee +++ b/examples/code.coffee @@ -135,7 +135,7 @@ aliquam erat volutpat. Ut wisi enim ad." # Inheritance and calling super. class Animal - constructor: (@name) -> + (@name) -> move: (meters) -> alert this.name + " moved " + meters + "m." diff --git a/examples/computer_science/linked_list.coffee b/examples/computer_science/linked_list.coffee index c59bb116..7774fb38 100644 --- a/examples/computer_science/linked_list.coffee +++ b/examples/computer_science/linked_list.coffee @@ -1,7 +1,7 @@ # "Classic" linked list implementation that doesn't keep track of its size. class LinkedList - constructor: -> + -> this._head = null # Pointer to the first item in the list. diff --git a/examples/potion.coffee b/examples/potion.coffee index 6092b486..fc5a817c 100644 --- a/examples/potion.coffee +++ b/examples/potion.coffee @@ -71,7 +71,7 @@ print p.name # Policeman ('Constable') print class Policeman extends Person - constructor: (@rank) -> + (@rank) -> print: -> print 'My name is ' + @name + " and I'm a " + @rank + '.' diff --git a/lib/nodes.js b/lib/nodes.js index f23bfdc5..25600435 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -851,25 +851,10 @@ base = assign.variable.base; delete assign.context; func = assign.value; - if (base.value === 'constructor') { - if (ctor) { - 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; - } + assign.variable = new Value(lname, [new Accessor(base, 'proto')]); + if (func instanceof Code && func.bound) { + boundFuncs.push(base); + func.bound = false; } } _results.push(assign); @@ -883,6 +868,15 @@ node = _ref[i]; if (node instanceof Value && node.isObject(true)) { 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 { others.push(node); } @@ -906,7 +900,7 @@ other = others[_i]; _fn(other); } - this.body.expressions = exps = flatten(exps); + this.body.expressions = exps = compact(flatten(exps)); if (!ctor) { ctor = new Code; if (this.parent) { diff --git a/src/nodes.coffee b/src/nodes.coffee index 6bc5b2c3..add0b8f1 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -157,7 +157,7 @@ exports.Expressions = class Expressions extends Base children: ['expressions'] - constructor: (nodes) -> + (nodes) -> @expressions = compact flatten nodes or [] # Tack an expression on to the end of this expression list. @@ -257,7 +257,7 @@ exports.Expressions = class Expressions extends Base # `true`, `false`, `null`... exports.Literal = class Literal extends Base - constructor: (@value) -> + (@value) -> makeReturn: -> if @isPureStatement() then this else new Return this @@ -292,7 +292,7 @@ exports.Return = class Return extends Base isStatement : YES isPureStatement: YES - constructor: (@expression) -> + (@expression) -> makeReturn: THIS @@ -313,7 +313,7 @@ exports.Value = class Value extends Base children: ['base', 'properties'] # 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 @base = base @properties = props or [] @@ -404,7 +404,7 @@ exports.Value = class Value extends Base # at the same position. exports.Comment = class Comment extends Base - constructor: (@comment) -> + (@comment) -> isPureStatement: YES isStatement: YES @@ -423,7 +423,7 @@ exports.Call = class Call extends Base children: ['variable', 'args'] - constructor: (variable, @args = [], @soak) -> + (variable, @args = [], @soak) -> @isNew = false @isSuper = variable is 'super' @variable = if @isSuper then null else variable @@ -526,7 +526,7 @@ exports.Extends = class Extends extends Base children: ['child', 'parent'] - constructor: (@child, @parent) -> + (@child, @parent) -> # Hooks one constructor into another's prototype chain. compile: (o) -> @@ -541,7 +541,7 @@ exports.Accessor = class Accessor extends Base children: ['name'] - constructor: (@name, tag) -> + (@name, tag) -> @proto = if tag is 'proto' then '.prototype' else '' @soak = tag is 'soak' @@ -558,7 +558,7 @@ exports.Index = class Index extends Base children: ['index'] - constructor: (@index) -> + (@index) -> compile: (o) -> (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]" @@ -573,7 +573,7 @@ exports.Obj = class Obj extends Base children: ['properties'] - constructor: (props, @generated = false) -> + (props, @generated = false) -> @objects = @properties = props or [] compileNode: (o) -> @@ -637,7 +637,7 @@ exports.Arr = class Arr extends Base children: ['objects'] - constructor: (objs) -> + (objs) -> @objects = objs or [] compileNode: (o) -> @@ -664,7 +664,7 @@ exports.Class = class Class extends Base # Initialize a **Class** with its name, an optional superclass, and a # 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 # 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 delete assign.context func = assign.value - if base.value is 'constructor' - if ctor - 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.variable = new Value(lname, [new Accessor(base, 'proto')]) + if func instanceof Code and func.bound + boundFuncs.push base + func.bound = no assign boundFuncs = [] @@ -717,6 +706,13 @@ exports.Class = class Class extends Base for node, i in exps = @body.expressions if node instanceof Value and node.isObject(true) 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 others.push node @@ -729,7 +725,7 @@ exports.Class = class Class extends Base n2.expressions[j] = compact convert expr2 n2.expressions = flatten n2.expressions - @body.expressions = exps = flatten exps + @body.expressions = exps = compact flatten exps unless ctor ctor = new Code if @parent @@ -762,7 +758,7 @@ exports.Assign = class Assign extends Base children: ['variable', 'value'] - constructor: (@variable, @value, @context) -> + (@variable, @value, @context) -> 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'] - constructor: (params, body, tag) -> + (params, body, tag) -> @params = params or [] @body = body or new Expressions @bound = tag is 'boundfunc' @@ -944,7 +940,7 @@ exports.Param = class Param extends Base children: ['name', 'value'] - constructor: (@name, @value, @splat) -> + (@name, @value, @splat) -> compile: (o) -> @name.compile o, LEVEL_LIST @@ -969,7 +965,7 @@ exports.Splat = class Splat extends Base isAssignable: YES - constructor: (name) -> + (name) -> @name = if name.compile then name else new Literal name assigns: (name) -> @@ -1009,7 +1005,7 @@ exports.While = class While extends Base isStatement: YES - constructor: (condition, options) -> + (condition, options) -> @condition = if options?.invert then condition.invert() else condition @guard = options?.guard @@ -1073,7 +1069,7 @@ exports.Op = class Op extends Base children: ['first', 'second'] - constructor: (op, first, second, flip) -> + (op, first, second, flip) -> return new In first, second if op is 'in' if op is 'new' return first.newInstance() if first instanceof Call @@ -1150,7 +1146,7 @@ exports.In = class In extends Base invert: NEGATE - constructor: (@object, @array) -> + (@object, @array) -> compileNode: (o) -> if @array instanceof Value and @array.isArray() @@ -1186,7 +1182,7 @@ exports.Try = class Try extends Base isStatement: YES - constructor: (@attempt, @error, @recovery, @ensure) -> + (@attempt, @error, @recovery, @ensure) -> makeReturn: -> @attempt = @attempt .makeReturn() if @attempt @@ -1217,7 +1213,7 @@ exports.Throw = class Throw extends Base isStatement: YES - constructor: (@expression) -> + (@expression) -> # A **Throw** is already a return, of sorts... makeReturn: THIS @@ -1236,7 +1232,7 @@ exports.Existence = class Existence extends Base invert: NEGATE - constructor: (@expression) -> + (@expression) -> compileNode: (o) -> code = @expression.compile o, LEVEL_OP @@ -1261,7 +1257,7 @@ exports.Parens = class Parens extends Base children: ['expression'] - constructor: (@expression) -> + (@expression) -> unwrap : -> @expression isComplex : -> @expression.isComplex() @@ -1291,7 +1287,7 @@ exports.For = class For extends Base isStatement: YES - constructor: (body, head) -> + (body, head) -> if head.index instanceof Value throw SyntaxError 'index cannot be a pattern matching expression' extend this, head @@ -1425,7 +1421,7 @@ exports.Switch = class Switch extends Base isStatement: YES - constructor: (@subject, @cases, @otherwise) -> + (@subject, @cases, @otherwise) -> makeReturn: -> pair[1].makeReturn() for pair in @cases @@ -1459,7 +1455,7 @@ exports.If = class If extends Base children: ['condition', 'body', 'elseBody'] - constructor: (condition, @body, options = {}) -> + (condition, @body, options = {}) -> @condition = if options.invert then condition.invert() else condition @elseBody = null @isChain = false diff --git a/src/optparse.coffee b/src/optparse.coffee index 3f486783..3b013d99 100644 --- a/src/optparse.coffee +++ b/src/optparse.coffee @@ -13,7 +13,7 @@ exports.OptionParser = class OptionParser # [short-flag, long-flag, description] # # Along with an an optional banner for the usage help. - constructor: (rules, @banner) -> + (rules, @banner) -> @rules = buildRules rules # Parse the list of arguments, populating an `options` object with all of the diff --git a/src/scope.coffee b/src/scope.coffee index ae8e11a9..60987260 100644 --- a/src/scope.coffee +++ b/src/scope.coffee @@ -17,7 +17,7 @@ exports.Scope = class Scope # 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 # it wraps. - constructor: (@parent, @expressions, @method) -> + (@parent, @expressions, @method) -> @variables = [{name: 'arguments', type: 'arguments'}] @positions = {} if @parent diff --git a/test/test_arguments.coffee b/test/test_arguments.coffee index 198332de..92686b06 100644 --- a/test/test_arguments.coffee +++ b/test/test_arguments.coffee @@ -35,7 +35,7 @@ eq context.arg, 3 eq context.arg.join(' '), '1 2 3' class Klass - constructor: (@one, @two) -> + (@one, @two) -> obj = new Klass 1, 2 diff --git a/test/test_classes.coffee b/test/test_classes.coffee index dfffa5b7..c9194170 100644 --- a/test/test_classes.coffee +++ b/test/test_classes.coffee @@ -18,7 +18,7 @@ thirdCtor = -> @array = [1, 2, 3] class ThirdChild extends SecondChild - constructor: -> thirdCtor.call this + -> thirdCtor.call this # Gratuitous comment for testing. func: (string) -> @@ -40,15 +40,15 @@ ok (new ThirdChild).array.join(' ') is '1 2 3' class TopClass - constructor: (arg) -> + (arg) -> @prop = 'top-' + arg class SuperClass extends TopClass - constructor: (arg) -> + (arg) -> super 'super-' + arg class SubClass extends SuperClass - constructor: -> + -> super 'sub' ok (new SubClass).prop is 'top-super-sub' @@ -57,7 +57,7 @@ ok (new SubClass).prop is 'top-super-sub' class OneClass @new = 'new' function: 'function' - constructor: (name) -> @name = name + (name) -> @name = name class TwoClass extends OneClass delete TwoClass.new @@ -131,10 +131,10 @@ ok obj.amI() # super() calls in constructors of classes that are defined as object properties. class Hive - constructor: (name) -> @name = name + (name) -> @name = name class Hive.Bee extends Hive - constructor: (name) -> super + (name) -> super maya = new Hive.Bee 'Maya' ok maya.name is 'Maya' @@ -154,7 +154,7 @@ ok instance.name() is 'class' # ... or statically, to the class. class Dog - constructor: (name) -> + (name) -> @name = name bark: => @@ -188,7 +188,7 @@ eq (func() for func in m.generate()).join(' '), '10 10 10' # Testing a contructor called with varargs. class Connection - constructor: (one, two, three) -> + (one, two, three) -> [@one, @two, @three] = [one, two, three] out: -> @@ -281,10 +281,12 @@ classMaker = -> @value = inner class One - constructor: classMaker() + ctor = classMaker() + -> ctor.call this class Two - constructor: classMaker() + ctor = classMaker() + -> ctor.call this ok (new One).value is 1 ok (new Two).value is 2 diff --git a/test/test_comprehensions.coffee b/test/test_comprehensions.coffee index 2a89f459..2195f6d1 100644 --- a/test/test_comprehensions.coffee +++ b/test/test_comprehensions.coffee @@ -146,7 +146,7 @@ ok expr(2, 4, 8).join(' ') is '4 16 64' # Fast object comprehensions over all properties, including prototypal ones. class Cat - constructor: -> @name = 'Whiskers' + -> @name = 'Whiskers' breed: 'tabby' hair: 'cream' diff --git a/test/test_existence.coffee b/test/test_existence.coffee index 8c8e2bb7..6ba016a3 100644 --- a/test/test_existence.coffee +++ b/test/test_existence.coffee @@ -81,7 +81,7 @@ eq ident(non?.existent().method()), undefined, 'soaks inner values' # Soaks constructor invocations. a = 0 class Foo - constructor: -> a += 1 + -> a += 1 bar: "bat" ok (new Foo())?.bar is 'bat'