From cb57a1ca1fd5656afdefa023e6c8669ed18f1a6a Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 8 Feb 2010 23:42:03 -0500 Subject: [PATCH] CoffeeScript-in-CoffeeScript can compile dotted accessors --- lib/coffee_script/lexer.js | 8 ++++---- lib/coffee_script/nodes.js | 22 +++++++++++++++++++--- src/lexer.coffee | 8 ++++---- src/nodes.coffee | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/lib/coffee_script/lexer.js b/lib/coffee_script/lexer.js index 720d56f1..a79a18b1 100644 --- a/lib/coffee_script/lexer.js +++ b/lib/coffee_script/lexer.js @@ -107,12 +107,12 @@ if (tag === 'IDENTIFIER' && this.value() === '::') { this.tag(-1, 'PROTOTYPE_ACCESS'); } - if (tag === 'IDENTIFIER' && this.value() === '.' && !(this.value(-2) === '.')) { - if (this.tag(-2) === '?') { - this.tag(-1, 'SOAK_ACCESS'); + if (tag === 'IDENTIFIER' && this.value() === '.' && !(this.value(2) === '.')) { + if (this.tag(2) === '?') { + this.tag(1, 'SOAK_ACCESS'); this.tokens.splice(-2, 1); } else { - this.tag(-1, 'PROPERTY_ACCESS'); + this.tag(1, 'PROPERTY_ACCESS'); } } this.token(tag, id); diff --git a/lib/coffee_script/nodes.js b/lib/coffee_script/nodes.js index 199c0ecd..947450e1 100644 --- a/lib/coffee_script/nodes.js +++ b/lib/coffee_script/nodes.js @@ -1,5 +1,5 @@ (function(){ - var CallNode, CommentNode, Expressions, ExtendsNode, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement; + var AccessorNode, CallNode, CommentNode, Expressions, ExtendsNode, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement; var __hasProp = Object.prototype.hasOwnProperty; process.mixin(require('./scope')); // The abstract base class for all CoffeeScript nodes. @@ -553,7 +553,8 @@ }, push: function push(prop) { this.properties.push(prop); - return this.children.push(prop); + this.children.push(prop); + return this; }, has_properties: function has_properties() { return this.properties.length || this.base instanceof ThisNode; @@ -640,7 +641,8 @@ }, push: function push(arg) { this.args.push(arg); - return this.children.push(arg); + this.children.push(arg); + return this; }, // Compile a vanilla function call. compile_node: function compile_node(o) { @@ -718,4 +720,18 @@ } })); statement(ExtendsNode); + // A dotted accessor into a part of a value, or the :: shorthand for + // an accessor into the object's prototype. + AccessorNode = (exports.AccessorNode = inherit(Node, { + constructor: function constructor(name, tag) { + this.name = name; + this.children = [this.name]; + this.prototype = tag === 'prototype'; + this.soak = tag === 'soak'; + return this; + }, + compile_node: function compile_node(o) { + return '.' + (this.prototype ? 'prototype.' : '') + this.name.compile(o); + } + })); })(); \ No newline at end of file diff --git a/src/lexer.coffee b/src/lexer.coffee index 086c60c9..e8b6852e 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -96,12 +96,12 @@ lex::identifier_token: -> tag: if KEYWORDS.indexOf(id) >= 0 then id.toUpperCase() else 'IDENTIFIER' tag: 'LEADING_WHEN' if tag is 'WHEN' and (this.tag() is 'OUTDENT' or this.tag() is 'INDENT') this.tag(-1, 'PROTOTYPE_ACCESS') if tag is 'IDENTIFIER' and this.value() is '::' - if tag is 'IDENTIFIER' and this.value() is '.' and !(this.value(-2) is '.') - if this.tag(-2) is '?' - this.tag(-1, 'SOAK_ACCESS') + if tag is 'IDENTIFIER' and this.value() is '.' and !(this.value(2) is '.') + if this.tag(2) is '?' + this.tag(1, 'SOAK_ACCESS') this.tokens.splice(-2, 1) else - this.tag(-1, 'PROPERTY_ACCESS') + this.tag(1, 'PROPERTY_ACCESS') this.token(tag, id) this.i += id.length true diff --git a/src/nodes.coffee b/src/nodes.coffee index be65e3af..8ddaf674 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -290,6 +290,7 @@ ValueNode: exports.ValueNode: inherit Node, { push: (prop) -> @properties.push(prop) @children.push(prop) + this has_properties: -> @properties.length or @base instanceof ThisNode @@ -377,6 +378,7 @@ CallNode: exports.CallNode: inherit Node, { push: (arg) -> @args.push(arg) @children.push(arg) + this # Compile a vanilla function call. compile_node: (o) -> @@ -441,6 +443,22 @@ ExtendsNode: exports.ExtendsNode: inherit Node, { statement ExtendsNode +# A dotted accessor into a part of a value, or the :: shorthand for +# an accessor into the object's prototype. +AccessorNode: exports.AccessorNode: inherit Node, { + + constructor: (name, tag) -> + @name: name + @children: [@name] + @prototype: tag is 'prototype' + @soak: tag is 'soak' + this + + compile_node: (o) -> + '.' + (if @prototype then 'prototype.' else '') + @name.compile(o) + +} +