allowing Klass::['dynamic-property'] syntax. Issue #392

This commit is contained in:
Jeremy Ashkenas
2010-05-31 22:32:43 -04:00
parent b8a4adbdc7
commit 45f442bd73
10 changed files with 178 additions and 167 deletions

View File

@@ -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.

View File

@@ -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.

View File

@@ -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;
})(); })();

File diff suppressed because one or more lines are too long

View File

@@ -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 = {};

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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