removing extensions from CoffeeScript

This commit is contained in:
Jeremy Ashkenas 2010-06-26 13:36:31 -04:00
parent b7faa4a7f2
commit f7345ffaac
10 changed files with 195 additions and 322 deletions

View File

@ -57,13 +57,6 @@
__dirname = path.dirname(__filename);
return eval(exports.compile(code, options));
});
// Extend CoffeeScript with a custom language extension. It should hook in to
// the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
// push a token on to the stack that contains a **Node** as the value (as a
// peer of the nodes in [nodes.coffee](nodes.html)).
exports.extend = function(func) {
return Lexer.extensions.push(func);
};
// The real Lexer produces a generic stream of tokens. This object provides a
// thin wrapper around it, compatible with the Jison API. We can then pass it
// directly as a "Jison lexer".

View File

@ -78,7 +78,7 @@
// CoffeeScript is the **Expression** -- everything that can be an expression
// is one. Expressions serve as the building blocks of many other rules, making
// them somewhat circular.
Expression: [o("Value"), o("Call"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Splat"), o("Existence"), o("Comment"), o("Extension")],
Expression: [o("Value"), o("Call"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Splat"), o("Existence"), o("Comment")],
// A an indented block of expressions. Note that the [Rewriter](rewriter.html)
// will convert some postfix forms into blocks for us, by adjusting the
// token stream.
@ -453,9 +453,6 @@
return new ParentheticalNode($2);
})
],
// A language extension to CoffeeScript from the outside. We simply pass
// it through unaltered.
Extension: [o("EXTENSION")],
// The condition portion of a while loop.
WhileSource: [
o("WHILE Expression", function() {

View File

@ -74,9 +74,6 @@
// short-circuiting if any of them succeed. Their order determines precedence:
// `@literalToken` is the fallback catch-all.
Lexer.prototype.extractNextToken = function() {
if (this.extensionToken()) {
return null;
}
if (this.identifierToken()) {
return null;
}
@ -108,19 +105,6 @@
};
// Tokenizers
// ----------
// Language extensions get the highest priority, first chance to tag tokens
// as something else.
Lexer.prototype.extensionToken = function() {
var _d, _e, _f, extension;
_e = Lexer.extensions;
for (_d = 0, _f = _e.length; _d < _f; _d++) {
extension = _e[_d];
if (extension.call(this)) {
return true;
}
}
return false;
};
// Matches identifying literals: variables, keywords, method names, etc.
// Check to ensure that JavaScript reserved words aren't being used as
// identifiers. Because CoffeeScript reserves a handful of keywords that are
@ -667,12 +651,8 @@
prev = this.prev(2);
return this.value() && this.value().match && this.value().match(NO_NEWLINE) && prev && (prev[0] !== '.') && !this.value().match(CODE);
};
// Lexer Properties
// ----------------
// There are no exensions to the core lexer by default.
Lexer.extensions = [];
return Lexer;
}).call(this);
})();
// Constants
// ---------
// Keywords that CoffeeScript shares in common with JavaScript.

File diff suppressed because one or more lines are too long

View File

@ -419,7 +419,7 @@
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@'];
// If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
// Tokens indicating that the implicit call must enclose a block of expressions.
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
// Tokens that always mark the end of an implicit call for single-liners.

View File

@ -55,13 +55,6 @@ exports.run: ((code, options) ->
eval exports.compile code, options
)
# Extend CoffeeScript with a custom language extension. It should hook in to
# the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
# push a token on to the stack that contains a **Node** as the value (as a
# peer of the nodes in [nodes.coffee](nodes.html)).
exports.extend: (func) ->
Lexer.extensions.push func
# The real Lexer produces a generic stream of tokens. This object provides a
# thin wrapper around it, compatible with the Jison API. We can then pass it
# directly as a "Jison lexer".

View File

@ -100,7 +100,6 @@ grammar: {
o "Splat"
o "Existence"
o "Comment"
o "Extension"
]
# A an indented block of expressions. Note that the [Rewriter](rewriter.html)
@ -396,12 +395,6 @@ grammar: {
o "( Line )", -> new ParentheticalNode $2
]
# A language extension to CoffeeScript from the outside. We simply pass
# it through unaltered.
Extension: [
o "EXTENSION"
]
# The condition portion of a while loop.
WhileSource: [
o "WHILE Expression", -> new WhileNode $2

View File

@ -60,7 +60,6 @@ exports.Lexer: class Lexer
# short-circuiting if any of them succeed. Their order determines precedence:
# `@literalToken` is the fallback catch-all.
extractNextToken: ->
return if @extensionToken()
return if @identifierToken()
return if @numberToken()
return if @heredocToken()
@ -75,13 +74,6 @@ exports.Lexer: class Lexer
# Tokenizers
# ----------
# Language extensions get the highest priority, first chance to tag tokens
# as something else.
extensionToken: ->
for extension in Lexer.extensions
return true if extension.call this
false
# Matches identifying literals: variables, keywords, method names, etc.
# Check to ensure that JavaScript reserved words aren't being used as
# identifiers. Because CoffeeScript reserves a handful of keywords that are
@ -451,12 +443,6 @@ exports.Lexer: class Lexer
@value() and @value().match and @value().match(NO_NEWLINE) and
prev and (prev[0] isnt '.') and not @value().match(CODE)
# Lexer Properties
# ----------------
# There are no exensions to the core lexer by default.
@extensions: []
# Constants
# ---------

View File

@ -282,7 +282,7 @@ IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@']
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION',
'TRY', 'DELETE', 'TYPEOF', 'SWITCH',
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!',
'THIS', 'NULL',
'@', '->', '=>', '[', '(', '{']

View File

@ -6,68 +6,3 @@ js: CoffeeScript.compile("one\r\ntwo", {noWrap: on})
ok js is "one;\ntwo;"
# Try out language extensions to CoffeeScript.
# Create the Node were going to add -- a literal syntax for splitting
# strings into letters.
class SplitNode extends BaseNode
type: 'Split'
constructor: (variable) ->
@variable: variable
compileNode: (o) ->
"'${@variable}'.split('')"
# Extend CoffeeScript with our lexing function that matches --wordgoeshere--
# and creates a SplitNode.
CoffeeScript.extend ->
return false unless variable: @match(/^--(\w+)--/, 1)
@i: + variable.length + 4
@token 'EXTENSION', new SplitNode(variable)
true
# Compile with the extension.
js: CoffeeScript.compile 'return --tobesplit--', {noWrap: on}
ok js is "return 'tobesplit'.split('');"
# Let's try a different extension, for Ruby-style array literals.
class WordArrayNode extends BaseNode
type: 'WordArray'
constructor: (words) ->
@words: words
compileNode: (o) ->
strings = ("\"$word\"" for word in @words).join ', '
"[$strings]"
CoffeeScript.extend ->
return false unless words: @chunk.match(/^%w\{(.*?)\}/)
@i: + words[0].length
@token 'EXTENSION', new WordArrayNode(words[1].split(/\s+/))
true
js: CoffeeScript.compile 'puts %w{one two three}', {noWrap: on}
ok js is 'puts(["one", "two", "three"]);'
# Finally, let's try an extension that converts `a << b` into `a.push(b)`.
CoffeeScript.extend ->
return false unless @chunk.match(/^<</)
@i: + 2
@token 'PROPERTY_ACCESS', '.'
@token 'IDENTIFIER', 'push'
js: CoffeeScript.compile 'a << b', {noWrap: on}
ok js is 'a.push(b);'
Lexer.extensions: []