mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 11:31:20 -05:00
allowing Klass::['dynamic-property'] syntax. Issue #392
This commit is contained in:
@@ -264,8 +264,12 @@
|
|||||||
Index: [
|
Index: [
|
||||||
o("INDEX_START Expression INDEX_END", function() {
|
o("INDEX_START Expression INDEX_END", function() {
|
||||||
return new IndexNode($2);
|
return new IndexNode($2);
|
||||||
}), o("SOAKED_INDEX_START Expression SOAKED_INDEX_END", function() {
|
}), o("INDEX_SOAK Index", function() {
|
||||||
return new IndexNode($2, 'soak');
|
$2.soak_node = true;
|
||||||
|
return $2;
|
||||||
|
}), o("INDEX_PROTO Index", function() {
|
||||||
|
$2.proto = true;
|
||||||
|
return $2;
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
// In CoffeeScript, an object literal is simply a list of assignments.
|
// In CoffeeScript, an object literal is simply a list of assignments.
|
||||||
|
|||||||
18
lib/lexer.js
18
lib/lexer.js
@@ -383,19 +383,17 @@
|
|||||||
}
|
}
|
||||||
} else if (value === ';') {
|
} else if (value === ';') {
|
||||||
tag = 'TERMINATOR';
|
tag = 'TERMINATOR';
|
||||||
} else if (value === '[' && this.tag() === '?' && !prev_spaced) {
|
|
||||||
tag = 'SOAKED_INDEX_START';
|
|
||||||
this.soaked_index = true;
|
|
||||||
this.tokens.pop();
|
|
||||||
} else if (value === ']' && this.soaked_index) {
|
|
||||||
tag = 'SOAKED_INDEX_END';
|
|
||||||
this.soaked_index = false;
|
|
||||||
} else if (include(CALLABLE, this.tag()) && !prev_spaced) {
|
} else if (include(CALLABLE, this.tag()) && !prev_spaced) {
|
||||||
if (value === '(') {
|
if (value === '(') {
|
||||||
tag = 'CALL_START';
|
tag = 'CALL_START';
|
||||||
}
|
} else if (value === '[') {
|
||||||
if (value === '[') {
|
|
||||||
tag = 'INDEX_START';
|
tag = 'INDEX_START';
|
||||||
|
if (this.tag() === '?') {
|
||||||
|
this.tag(1, 'INDEX_SOAK');
|
||||||
|
}
|
||||||
|
if (this.tag() === '::') {
|
||||||
|
this.tag(1, 'INDEX_PROTO');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.i += value.length;
|
this.i += value.length;
|
||||||
@@ -692,7 +690,7 @@
|
|||||||
// Tokens which could legitimately be invoked or indexed. A opening
|
// Tokens which could legitimately be invoked or indexed. A opening
|
||||||
// parentheses or bracket following these tokens will be recorded as the start
|
// parentheses or bracket following these tokens will be recorded as the start
|
||||||
// of a function invocation or indexing operation.
|
// of a function invocation or indexing operation.
|
||||||
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS'];
|
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::'];
|
||||||
// Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
// Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
||||||
// occurs at the start of a line. We disambiguate these from trailing whens to
|
// occurs at the start of a line. We disambiguate these from trailing whens to
|
||||||
// avoid an ambiguity in the grammar.
|
// avoid an ambiguity in the grammar.
|
||||||
|
|||||||
@@ -700,19 +700,19 @@
|
|||||||
//### IndexNode
|
//### IndexNode
|
||||||
// A `[ ... ]` indexed accessor into an array or object.
|
// A `[ ... ]` indexed accessor into an array or object.
|
||||||
exports.IndexNode = (function() {
|
exports.IndexNode = (function() {
|
||||||
IndexNode = function(index, tag) {
|
IndexNode = function(index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.soak_node = tag === 'soak';
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(IndexNode, BaseNode);
|
__extends(IndexNode, BaseNode);
|
||||||
IndexNode.prototype.type = 'IndexNode';
|
IndexNode.prototype.type = 'IndexNode';
|
||||||
IndexNode.prototype.children = ['index'];
|
IndexNode.prototype.children = ['index'];
|
||||||
IndexNode.prototype.compile_node = function(o) {
|
IndexNode.prototype.compile_node = function(o) {
|
||||||
var idx;
|
var idx, prefix;
|
||||||
o.chain_root.wrapped = o.chain_root.wrapped || this.soak_node;
|
o.chain_root.wrapped = o.chain_root.wrapped || this.soak_node;
|
||||||
idx = this.index.compile(o);
|
idx = this.index.compile(o);
|
||||||
return "[" + idx + "]";
|
prefix = this.proto ? '.prototype' : '';
|
||||||
|
return "" + prefix + "[" + idx + "]";
|
||||||
};
|
};
|
||||||
return IndexNode;
|
return IndexNode;
|
||||||
})();
|
})();
|
||||||
|
|||||||
274
lib/parser.js
274
lib/parser.js
File diff suppressed because one or more lines are too long
@@ -350,7 +350,7 @@
|
|||||||
// Constants
|
// Constants
|
||||||
// ---------
|
// ---------
|
||||||
// List of the token pairs that must be balanced.
|
// List of the token pairs that must be balanced.
|
||||||
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']];
|
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END']];
|
||||||
// The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
// The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
||||||
// look things up from either end.
|
// look things up from either end.
|
||||||
INVERSES = {};
|
INVERSES = {};
|
||||||
|
|||||||
@@ -253,7 +253,8 @@ grammar: {
|
|||||||
# Indexing into an object or array using bracket notation.
|
# Indexing into an object or array using bracket notation.
|
||||||
Index: [
|
Index: [
|
||||||
o "INDEX_START Expression INDEX_END", -> new IndexNode $2
|
o "INDEX_START Expression INDEX_END", -> new IndexNode $2
|
||||||
o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode $2, 'soak'
|
o "INDEX_SOAK Index", -> $2.soak_node: yes; $2
|
||||||
|
o "INDEX_PROTO Index", -> $2.proto: yes; $2
|
||||||
]
|
]
|
||||||
|
|
||||||
# In CoffeeScript, an object literal is simply a list of assignments.
|
# In CoffeeScript, an object literal is simply a list of assignments.
|
||||||
|
|||||||
@@ -263,16 +263,13 @@ exports.Lexer: class Lexer
|
|||||||
@assignment_error() if include JS_FORBIDDEN, @value
|
@assignment_error() if include JS_FORBIDDEN, @value
|
||||||
else if value is ';'
|
else if value is ';'
|
||||||
tag: 'TERMINATOR'
|
tag: 'TERMINATOR'
|
||||||
else if value is '[' and @tag() is '?' and not prev_spaced
|
|
||||||
tag: 'SOAKED_INDEX_START'
|
|
||||||
@soaked_index: true
|
|
||||||
@tokens.pop()
|
|
||||||
else if value is ']' and @soaked_index
|
|
||||||
tag: 'SOAKED_INDEX_END'
|
|
||||||
@soaked_index: false
|
|
||||||
else if include(CALLABLE, @tag()) and not prev_spaced
|
else if include(CALLABLE, @tag()) and not prev_spaced
|
||||||
tag: 'CALL_START' if value is '('
|
if value is '('
|
||||||
tag: 'INDEX_START' if value is '['
|
tag: 'CALL_START'
|
||||||
|
else if value is '['
|
||||||
|
tag: 'INDEX_START'
|
||||||
|
@tag 1, 'INDEX_SOAK' if @tag() is '?'
|
||||||
|
@tag 1, 'INDEX_PROTO' if @tag() is '::'
|
||||||
@i: + value.length
|
@i: + value.length
|
||||||
return @tag_half_assignment tag if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
return @tag_half_assignment tag if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||||
@token tag, value
|
@token tag, value
|
||||||
@@ -522,7 +519,7 @@ NOT_REGEX: [
|
|||||||
# Tokens which could legitimately be invoked or indexed. A opening
|
# Tokens which could legitimately be invoked or indexed. A opening
|
||||||
# parentheses or bracket following these tokens will be recorded as the start
|
# parentheses or bracket following these tokens will be recorded as the start
|
||||||
# of a function invocation or indexing operation.
|
# of a function invocation or indexing operation.
|
||||||
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS']
|
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::']
|
||||||
|
|
||||||
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
||||||
# occurs at the start of a line. We disambiguate these from trailing whens to
|
# occurs at the start of a line. We disambiguate these from trailing whens to
|
||||||
|
|||||||
@@ -509,14 +509,14 @@ exports.IndexNode: class IndexNode extends BaseNode
|
|||||||
type: 'IndexNode'
|
type: 'IndexNode'
|
||||||
children: ['index']
|
children: ['index']
|
||||||
|
|
||||||
constructor: (index, tag) ->
|
constructor: (index) ->
|
||||||
@index: index
|
@index: index
|
||||||
@soak_node: tag is 'soak'
|
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
o.chain_root.wrapped: or @soak_node
|
o.chain_root.wrapped: or @soak_node
|
||||||
idx: @index.compile o
|
idx: @index.compile o
|
||||||
"[$idx]"
|
prefix: if @proto then '.prototype' else ''
|
||||||
|
"$prefix[$idx]"
|
||||||
|
|
||||||
#### RangeNode
|
#### RangeNode
|
||||||
|
|
||||||
|
|||||||
@@ -254,8 +254,7 @@ exports.Rewriter: class Rewriter
|
|||||||
|
|
||||||
# List of the token pairs that must be balanced.
|
# List of the token pairs that must be balanced.
|
||||||
BALANCED_PAIRS: [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'],
|
BALANCED_PAIRS: [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'],
|
||||||
['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'],
|
['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END']]
|
||||||
['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']]
|
|
||||||
|
|
||||||
# The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
# The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
||||||
# look things up from either end.
|
# look things up from either end.
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ ok (new TwoClass('three')).name is 'three'
|
|||||||
Base: ->
|
Base: ->
|
||||||
Base::func: (string) ->
|
Base::func: (string) ->
|
||||||
'zero/' + string
|
'zero/' + string
|
||||||
|
Base::['func-func']: (string) ->
|
||||||
|
"dynamic-$string"
|
||||||
|
|
||||||
FirstChild: ->
|
FirstChild: ->
|
||||||
FirstChild extends Base
|
FirstChild extends Base
|
||||||
@@ -77,6 +79,8 @@ result: (new ThirdChild()).func 'four'
|
|||||||
|
|
||||||
ok result is 'zero/one/two/three/four'
|
ok result is 'zero/one/two/three/four'
|
||||||
|
|
||||||
|
ok (new ThirdChild())['func-func']('thing') is 'dynamic-thing'
|
||||||
|
|
||||||
|
|
||||||
TopClass: (arg) ->
|
TopClass: (arg) ->
|
||||||
@prop: 'top-' + arg
|
@prop: 'top-' + arg
|
||||||
|
|||||||
Reference in New Issue
Block a user