mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
fixes #1234 ... :: now creates an intermediary "prototype" Access node before any additional property accesses
This commit is contained in:
parent
e5b77b180a
commit
29a44b84d5
7 changed files with 33 additions and 26 deletions
|
@ -135,7 +135,7 @@
|
||||||
o('Identifier', function() {
|
o('Identifier', function() {
|
||||||
return new Value($1);
|
return new Value($1);
|
||||||
}), o('Value Accessor', function() {
|
}), o('Value Accessor', function() {
|
||||||
return $1.push($2);
|
return $1.concat($2);
|
||||||
}), o('Invocation Accessor', function() {
|
}), o('Invocation Accessor', function() {
|
||||||
return new Value($1, [$2]);
|
return new Value($1, [$2]);
|
||||||
}), o('ThisProperty')
|
}), o('ThisProperty')
|
||||||
|
@ -162,7 +162,7 @@
|
||||||
}), o('?. Identifier', function() {
|
}), o('?. Identifier', function() {
|
||||||
return new Access($2, 'soak');
|
return new Access($2, 'soak');
|
||||||
}), o(':: Identifier', function() {
|
}), o(':: Identifier', function() {
|
||||||
return new Access($2, 'proto');
|
return [new Access(new Literal('prototype')), new Access($2)];
|
||||||
}), o('::', function() {
|
}), o('::', function() {
|
||||||
return new Access(new Literal('prototype'));
|
return new Access(new Literal('prototype'));
|
||||||
}), o('Index')
|
}), o('Index')
|
||||||
|
|
|
@ -344,9 +344,6 @@
|
||||||
switch (prev[0]) {
|
switch (prev[0]) {
|
||||||
case '?':
|
case '?':
|
||||||
prev[0] = 'INDEX_SOAK';
|
prev[0] = 'INDEX_SOAK';
|
||||||
break;
|
|
||||||
case '::':
|
|
||||||
prev[0] = 'INDEX_PROTO';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,6 +382,10 @@
|
||||||
this.properties.push(prop);
|
this.properties.push(prop);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
Value.prototype.concat = function(props) {
|
||||||
|
this.properties = this.properties.concat(props);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
Value.prototype.hasProperties = function() {
|
Value.prototype.hasProperties = function() {
|
||||||
return !!this.properties.length;
|
return !!this.properties.length;
|
||||||
};
|
};
|
||||||
|
@ -686,14 +690,17 @@
|
||||||
function Access(name, tag) {
|
function Access(name, tag) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.name.asKey = true;
|
this.name.asKey = true;
|
||||||
this.proto = tag === 'proto' ? '.prototype' : '';
|
|
||||||
this.soak = tag === 'soak';
|
this.soak = tag === 'soak';
|
||||||
}
|
}
|
||||||
Access.prototype.children = ['name'];
|
Access.prototype.children = ['name'];
|
||||||
Access.prototype.compile = function(o) {
|
Access.prototype.compile = function(o) {
|
||||||
var name;
|
var name;
|
||||||
name = this.name.compile(o);
|
name = this.name.compile(o);
|
||||||
return this.proto + (IDENTIFIER.test(name) ? "." + name : "[" + name + "]");
|
if (IDENTIFIER.test(name)) {
|
||||||
|
return "." + name;
|
||||||
|
} else {
|
||||||
|
return "[" + name + "]";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Access.prototype.isComplex = NO;
|
Access.prototype.isComplex = NO;
|
||||||
return Access;
|
return Access;
|
||||||
|
@ -705,7 +712,7 @@
|
||||||
}
|
}
|
||||||
Index.prototype.children = ['index'];
|
Index.prototype.children = ['index'];
|
||||||
Index.prototype.compile = function(o) {
|
Index.prototype.compile = function(o) {
|
||||||
return (this.proto ? '.prototype' : '') + ("[" + (this.index.compile(o, LEVEL_PAREN)) + "]");
|
return "[" + (this.index.compile(o, LEVEL_PAREN)) + "]";
|
||||||
};
|
};
|
||||||
Index.prototype.isComplex = function() {
|
Index.prototype.isComplex = function() {
|
||||||
return this.index.isComplex();
|
return this.index.isComplex();
|
||||||
|
@ -970,11 +977,11 @@
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!assign.variable["this"]) {
|
if (!assign.variable["this"]) {
|
||||||
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')]);
|
assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]);
|
||||||
}
|
if (func instanceof Code && func.bound) {
|
||||||
if (func instanceof Code && func.bound && !assign.variable["this"]) {
|
this.boundFuncs.push(base);
|
||||||
this.boundFuncs.push(base);
|
func.bound = false;
|
||||||
func.bound = false;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ case 61:this.$ = new yy.Splat($$[$0-1]);
|
||||||
break;
|
break;
|
||||||
case 62:this.$ = new yy.Value($$[$0]);
|
case 62:this.$ = new yy.Value($$[$0]);
|
||||||
break;
|
break;
|
||||||
case 63:this.$ = $$[$0-1].push($$[$0]);
|
case 63:this.$ = $$[$0-1].concat($$[$0]);
|
||||||
break;
|
break;
|
||||||
case 64:this.$ = new yy.Value($$[$0-1], [$$[$0]]);
|
case 64:this.$ = new yy.Value($$[$0-1], [$$[$0]]);
|
||||||
break;
|
break;
|
||||||
|
@ -164,7 +164,7 @@ case 74:this.$ = new yy.Access($$[$0]);
|
||||||
break;
|
break;
|
||||||
case 75:this.$ = new yy.Access($$[$0], 'soak');
|
case 75:this.$ = new yy.Access($$[$0], 'soak');
|
||||||
break;
|
break;
|
||||||
case 76:this.$ = new yy.Access($$[$0], 'proto');
|
case 76:this.$ = [new yy.Access(new yy.Literal('prototype')), new yy.Access($$[$0])];
|
||||||
break;
|
break;
|
||||||
case 77:this.$ = new yy.Access(new yy.Literal('prototype'));
|
case 77:this.$ = new yy.Access(new yy.Literal('prototype'));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -217,7 +217,7 @@ grammar =
|
||||||
# Variables and properties that can be assigned to.
|
# Variables and properties that can be assigned to.
|
||||||
SimpleAssignable: [
|
SimpleAssignable: [
|
||||||
o 'Identifier', -> new Value $1
|
o 'Identifier', -> new Value $1
|
||||||
o 'Value Accessor', -> $1.push $2
|
o 'Value Accessor', -> $1.concat $2
|
||||||
o 'Invocation Accessor', -> new Value $1, [$2]
|
o 'Invocation Accessor', -> new Value $1, [$2]
|
||||||
o 'ThisProperty'
|
o 'ThisProperty'
|
||||||
]
|
]
|
||||||
|
@ -244,7 +244,7 @@ grammar =
|
||||||
Accessor: [
|
Accessor: [
|
||||||
o '. Identifier', -> new Access $2
|
o '. Identifier', -> new Access $2
|
||||||
o '?. Identifier', -> new Access $2, 'soak'
|
o '?. Identifier', -> new Access $2, 'soak'
|
||||||
o ':: Identifier', -> new Access $2, 'proto'
|
o ':: Identifier', -> [(new Access new Literal 'prototype'), new Access $2]
|
||||||
o '::', -> new Access new Literal 'prototype'
|
o '::', -> new Access new Literal 'prototype'
|
||||||
o 'Index'
|
o 'Index'
|
||||||
]
|
]
|
||||||
|
|
|
@ -336,7 +336,6 @@ exports.Lexer = class Lexer
|
||||||
tag = 'INDEX_START'
|
tag = 'INDEX_START'
|
||||||
switch prev[0]
|
switch prev[0]
|
||||||
when '?' then prev[0] = 'INDEX_SOAK'
|
when '?' then prev[0] = 'INDEX_SOAK'
|
||||||
when '::' then prev[0] = 'INDEX_PROTO'
|
|
||||||
@token tag, value
|
@token tag, value
|
||||||
value.length
|
value.length
|
||||||
|
|
||||||
|
|
|
@ -344,10 +344,15 @@ exports.Value = class Value extends Base
|
||||||
|
|
||||||
children: ['base', 'properties']
|
children: ['base', 'properties']
|
||||||
|
|
||||||
# Add a property access to the list.
|
# Add a property `Access` to the list.
|
||||||
push: (prop) ->
|
push: (prop) ->
|
||||||
@properties.push prop
|
@properties.push prop
|
||||||
this
|
this
|
||||||
|
|
||||||
|
# Add multiple property `Access`s to the list.
|
||||||
|
concat: (props) ->
|
||||||
|
@properties = @properties.concat props
|
||||||
|
this
|
||||||
|
|
||||||
hasProperties: ->
|
hasProperties: ->
|
||||||
!!@properties.length
|
!!@properties.length
|
||||||
|
@ -596,14 +601,13 @@ exports.Extends = class Extends extends Base
|
||||||
exports.Access = class Access extends Base
|
exports.Access = class Access extends Base
|
||||||
constructor: (@name, tag) ->
|
constructor: (@name, tag) ->
|
||||||
@name.asKey = yes
|
@name.asKey = yes
|
||||||
@proto = if tag is 'proto' then '.prototype' else ''
|
|
||||||
@soak = tag is 'soak'
|
@soak = tag is 'soak'
|
||||||
|
|
||||||
children: ['name']
|
children: ['name']
|
||||||
|
|
||||||
compile: (o) ->
|
compile: (o) ->
|
||||||
name = @name.compile o
|
name = @name.compile o
|
||||||
@proto + if IDENTIFIER.test name then ".#{name}" else "[#{name}]"
|
if IDENTIFIER.test name then ".#{name}" else "[#{name}]"
|
||||||
|
|
||||||
isComplex: NO
|
isComplex: NO
|
||||||
|
|
||||||
|
@ -616,7 +620,7 @@ exports.Index = class Index extends Base
|
||||||
children: ['index']
|
children: ['index']
|
||||||
|
|
||||||
compile: (o) ->
|
compile: (o) ->
|
||||||
(if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"
|
"[#{ @index.compile o, LEVEL_PAREN }]"
|
||||||
|
|
||||||
isComplex: ->
|
isComplex: ->
|
||||||
@index.isComplex()
|
@index.isComplex()
|
||||||
|
@ -857,10 +861,10 @@ exports.Class = class Class extends Base
|
||||||
assign = new Assign new Literal(@externalCtor), func
|
assign = new Assign new Literal(@externalCtor), func
|
||||||
else
|
else
|
||||||
unless assign.variable.this
|
unless assign.variable.this
|
||||||
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
|
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
|
||||||
if func instanceof Code and func.bound and not assign.variable.this
|
if func instanceof Code and func.bound
|
||||||
@boundFuncs.push base
|
@boundFuncs.push base
|
||||||
func.bound = no
|
func.bound = no
|
||||||
assign
|
assign
|
||||||
compact exprs
|
compact exprs
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue