(experimental) made `new` a unary operator
This commit is contained in:
parent
9a3b736174
commit
c24e1eacb9
|
@ -53,7 +53,7 @@
|
|||
__dirname = path.dirname(__filename);
|
||||
return eval(exports.compile(code, options));
|
||||
};
|
||||
lexer = new Lexer();
|
||||
lexer = new Lexer;
|
||||
parser.lexer = {
|
||||
lex: function() {
|
||||
var token;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
exec = _ref.exec;
|
||||
_ref = require('events');
|
||||
EventEmitter = _ref.EventEmitter;
|
||||
helpers.extend(CoffeeScript, new EventEmitter());
|
||||
helpers.extend(CoffeeScript, new EventEmitter);
|
||||
global.CoffeeScript = CoffeeScript;
|
||||
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee';
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
grammar = {
|
||||
Root: [
|
||||
o("", function() {
|
||||
return new Expressions();
|
||||
return new Expressions;
|
||||
}), o("TERMINATOR", function() {
|
||||
return new Expressions();
|
||||
return new Expressions;
|
||||
}), o("Body"), o("Block TERMINATOR")
|
||||
],
|
||||
Body: [
|
||||
|
@ -37,12 +37,12 @@
|
|||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
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("Existence"), o("Comment")],
|
||||
Expression: [o("Value"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Existence"), o("Comment")],
|
||||
Block: [
|
||||
o("INDENT Body OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("INDENT OUTDENT", function() {
|
||||
return new Expressions();
|
||||
return new Expressions;
|
||||
}), o("TERMINATOR Comment", function() {
|
||||
return Expressions.wrap([$2]);
|
||||
})
|
||||
|
@ -257,13 +257,6 @@
|
|||
return $2;
|
||||
})
|
||||
],
|
||||
Call: [
|
||||
o("Invocation"), o("NEW Invocation", function() {
|
||||
return $2.newInstance();
|
||||
}), o("NEW Value", function() {
|
||||
return (new CallNode($2, [])).newInstance();
|
||||
})
|
||||
],
|
||||
Extends: [
|
||||
o("SimpleAssignable EXTENDS Value", function() {
|
||||
return new ExtendsNode($1, $3);
|
||||
|
@ -611,7 +604,7 @@
|
|||
})
|
||||
]
|
||||
};
|
||||
operators = [["right", '?', 'NEW'], ["left", 'CALL_START', 'CALL_END'], ["nonassoc", '++', '--'], ["right", 'UNARY'], ["left", 'MATH'], ["left", '+', '-'], ["left", 'SHIFT'], ["left", 'COMPARE'], ["left", 'INSTANCEOF'], ["left", '==', '!='], ["left", 'LOGIC'], ["right", 'COMPOUND_ASSIGN'], ["left", '.'], ["nonassoc", 'INDENT', 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS'], ["right", '=', ':', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'POST_IF', 'POST_UNLESS']];
|
||||
operators = [["right", '?'], ["left", 'CALL_START', 'CALL_END'], ["nonassoc", '++', '--'], ["right", 'UNARY'], ["left", 'MATH'], ["left", '+', '-'], ["left", 'SHIFT'], ["left", 'COMPARE'], ["left", 'INSTANCEOF'], ["left", '==', '!='], ["left", 'LOGIC'], ["right", 'COMPOUND_ASSIGN'], ["left", '.'], ["nonassoc", 'INDENT', 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS'], ["right", '=', ':', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'POST_IF', 'POST_UNLESS']];
|
||||
tokens = [];
|
||||
_ref = grammar;
|
||||
for (name in _ref) {
|
||||
|
|
10
lib/lexer.js
10
lib/lexer.js
|
@ -29,7 +29,7 @@
|
|||
if (o.rewrite === false) {
|
||||
return this.tokens;
|
||||
}
|
||||
return (new Rewriter()).rewrite(this.tokens);
|
||||
return (new Rewriter).rewrite(this.tokens);
|
||||
};
|
||||
Lexer.prototype.extractNextToken = function() {
|
||||
return this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
|
||||
|
@ -185,7 +185,7 @@
|
|||
if (REGEX_INTERPOLATION.test(regex)) {
|
||||
str = regex.slice(1, -1);
|
||||
str = str.replace(REGEX_ESCAPE, '\\$&');
|
||||
this.tokens.push(['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']);
|
||||
this.tokens.push(['(', '('], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']);
|
||||
this.interpolateString("\"" + (str) + "\"", {
|
||||
escapeQuotes: true
|
||||
});
|
||||
|
@ -474,7 +474,7 @@
|
|||
if (str.length < 3 || str.charAt(0) !== '"') {
|
||||
return this.token('STRING', str);
|
||||
} else {
|
||||
lexer = new Lexer();
|
||||
lexer = new Lexer;
|
||||
tokens = [];
|
||||
quote = str.charAt(0);
|
||||
_ref2 = [1, 1];
|
||||
|
@ -605,12 +605,12 @@
|
|||
REGEX_END = /^[imgy]{0,4}(?![a-zA-Z])/;
|
||||
REGEX_ESCAPE = /\\[^#]/g;
|
||||
MULTILINER = /\n/g;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|not|delete|typeof|instanceof)$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
HEREDOC_INDENT = /\n+([ \t]*)|^([ \t]+)/g;
|
||||
ASSIGNED = /^\s*((?:[a-zA-Z$_@]\w*|["'][^\n]+?["']|\d+)[ \t]*?[:=][^:=])/;
|
||||
NEXT_CHARACTER = /^\s*(\S)/;
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'TYPEOF', 'DELETE'];
|
||||
UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'NEW', 'TYPEOF', 'DELETE'];
|
||||
LOGIC = ['&', '|', '^', '&&', '||'];
|
||||
SHIFT = ['<<', '>>', '>>>'];
|
||||
COMPARE = ['<=', '<', '>', '>='];
|
||||
|
|
10
lib/nodes.js
10
lib/nodes.js
|
@ -868,7 +868,7 @@
|
|||
this.variable = literal(o.scope.freeVariable('ctor'));
|
||||
}
|
||||
extension = this.parent && new ExtendsNode(this.variable, this.parent);
|
||||
props = new Expressions();
|
||||
props = new Expressions;
|
||||
o.top = true;
|
||||
me = null;
|
||||
className = this.variable.compile(o);
|
||||
|
@ -877,7 +877,7 @@
|
|||
applied = new ValueNode(this.parent, [new AccessorNode(literal('apply'))]);
|
||||
constructor = new CodeNode([], new Expressions([new CallNode(applied, [literal('this'), literal('arguments')])]));
|
||||
} else {
|
||||
constructor = new CodeNode();
|
||||
constructor = new CodeNode;
|
||||
}
|
||||
_ref2 = this.properties;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
|
@ -1055,7 +1055,7 @@
|
|||
this.params = _arg;
|
||||
CodeNode.__super__.constructor.call(this);
|
||||
this.params || (this.params = []);
|
||||
this.body || (this.body = new Expressions());
|
||||
this.body || (this.body = (new Expressions));
|
||||
this.bound = tag === 'boundfunc';
|
||||
if (this.bound) {
|
||||
this.context = 'this';
|
||||
|
@ -1311,6 +1311,8 @@
|
|||
this.flip = !!flip;
|
||||
if (this.first instanceof ValueNode && this.first.base instanceof ObjectNode) {
|
||||
this.first = new ParentheticalNode(this.first);
|
||||
} else if (this.operator === 'new' && this.first instanceof CallNode) {
|
||||
return this.first.newInstance();
|
||||
}
|
||||
this.first.tags.operation = true;
|
||||
if (this.second) {
|
||||
|
@ -1329,7 +1331,7 @@
|
|||
};
|
||||
OpNode.prototype.CHAINABLE = ['<', '>', '>=', '<=', '===', '!=='];
|
||||
OpNode.prototype.ASSIGNMENT = ['||=', '&&=', '?='];
|
||||
OpNode.prototype.PREFIX_OPERATORS = ['typeof', 'delete'];
|
||||
OpNode.prototype.PREFIX_OPERATORS = ['new', 'typeof', 'delete'];
|
||||
OpNode.prototype["class"] = 'OpNode';
|
||||
OpNode.prototype.children = ['first', 'second'];
|
||||
OpNode.prototype.isUnary = function() {
|
||||
|
|
|
@ -9,9 +9,9 @@ performAction: function anonymous(yytext,yyleng,yylineno,yy) {
|
|||
|
||||
var $$ = arguments[5],$0=arguments[5].length;
|
||||
switch(arguments[4]) {
|
||||
case 1:return this.$ = new yy.Expressions();
|
||||
case 1:return this.$ = new yy.Expressions;
|
||||
break;
|
||||
case 2:return this.$ = new yy.Expressions();
|
||||
case 2:return this.$ = new yy.Expressions;
|
||||
break;
|
||||
case 3:return this.$ = $$[$0-1+1-1];
|
||||
break;
|
||||
|
@ -67,7 +67,7 @@ case 28:this.$ = $$[$0-1+1-1];
|
|||
break;
|
||||
case 29:this.$ = $$[$0-3+2-1];
|
||||
break;
|
||||
case 30:this.$ = new yy.Expressions();
|
||||
case 30:this.$ = new yy.Expressions;
|
||||
break;
|
||||
case 31:this.$ = yy.Expressions.wrap([$$[$0-2+2-1]]);
|
||||
break;
|
||||
|
@ -701,7 +701,7 @@ exports.main = function commonjsMain(args) {
|
|||
}
|
||||
return exports.parser.parse(source);
|
||||
}
|
||||
if (typeof module !== "undefined" && require.main === module) {
|
||||
if (typeof module !== 'undefined' && require.main === module) {
|
||||
exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
|
||||
}
|
||||
}
|
|
@ -88,7 +88,6 @@ grammar =
|
|||
# them somewhat circular.
|
||||
Expression: [
|
||||
o "Value"
|
||||
o "Call"
|
||||
o "Code"
|
||||
o "Operation"
|
||||
o "Assign"
|
||||
|
@ -298,13 +297,6 @@ grammar =
|
|||
o "{ ClassBody }", -> $2
|
||||
]
|
||||
|
||||
# The two flavors of function call: normal, and object instantiation with `new`.
|
||||
Call: [
|
||||
o "Invocation"
|
||||
o "NEW Invocation", -> $2.newInstance()
|
||||
o "NEW Value", -> (new CallNode($2, [])).newInstance()
|
||||
]
|
||||
|
||||
# Extending an object by setting its prototype chain to reference a parent
|
||||
# object.
|
||||
Extends: [
|
||||
|
@ -575,7 +567,7 @@ grammar =
|
|||
#
|
||||
# (2 + 3) * 4
|
||||
operators = [
|
||||
["right", '?', 'NEW']
|
||||
["right", '?']
|
||||
["left", 'CALL_START', 'CALL_END']
|
||||
["nonassoc", '++', '--']
|
||||
["right", 'UNARY']
|
||||
|
|
|
@ -178,7 +178,7 @@ exports.Lexer = class Lexer
|
|||
if REGEX_INTERPOLATION.test regex
|
||||
str = regex.slice 1, -1
|
||||
str = str.replace REGEX_ESCAPE, '\\$&'
|
||||
@tokens.push ['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']
|
||||
@tokens.push ['(', '('], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']
|
||||
@interpolateString "\"#{str}\"", escapeQuotes: yes
|
||||
@tokens.push [',', ','], ['STRING', "\"#{flags}\""] if flags
|
||||
@tokens.push [')', ')'], [')', ')']
|
||||
|
@ -553,7 +553,7 @@ REGEX_ESCAPE = /\\[^#]/g
|
|||
|
||||
# Token cleaning regexes.
|
||||
MULTILINER = /\n/g
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|not|delete|typeof|instanceof)$/
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/
|
||||
HEREDOC_INDENT = /\n+([ \t]*)|^([ \t]+)/g
|
||||
ASSIGNED = /^\s*((?:[a-zA-Z$_@]\w*|["'][^\n]+?["']|\d+)[ \t]*?[:=][^:=])/
|
||||
NEXT_CHARACTER = /^\s*(\S)/
|
||||
|
@ -562,7 +562,7 @@ NEXT_CHARACTER = /^\s*(\S)/
|
|||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']
|
||||
|
||||
# Unary tokens.
|
||||
UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'TYPEOF', 'DELETE']
|
||||
UNARY = ['UMINUS', 'UPLUS', '!', '!!', '~', 'NEW', 'TYPEOF', 'DELETE']
|
||||
|
||||
# Logical tokens.
|
||||
LOGIC = ['&', '|', '^', '&&', '||']
|
||||
|
|
|
@ -1121,7 +1121,7 @@ exports.OpNode = class OpNode extends BaseNode
|
|||
ASSIGNMENT: ['||=', '&&=', '?=']
|
||||
|
||||
# Operators must come before their operands with a space.
|
||||
PREFIX_OPERATORS: ['typeof', 'delete']
|
||||
PREFIX_OPERATORS: ['new', 'typeof', 'delete']
|
||||
|
||||
class: 'OpNode'
|
||||
children: ['first', 'second']
|
||||
|
@ -1132,6 +1132,8 @@ exports.OpNode = class OpNode extends BaseNode
|
|||
@flip = !!flip
|
||||
if @first instanceof ValueNode and @first.base instanceof ObjectNode
|
||||
@first = new ParentheticalNode @first
|
||||
else if @operator is 'new' and @first instanceof CallNode
|
||||
return @first.newInstance()
|
||||
@first.tags.operation = yes
|
||||
@second.tags.operation = yes if @second
|
||||
|
||||
|
|
|
@ -156,5 +156,6 @@ ok c is 3
|
|||
|
||||
|
||||
# Instanceof.
|
||||
ok new String instanceof String
|
||||
ok new Number not instanceof String
|
||||
# FIXME: These parentheses are workaround of #
|
||||
ok (new String) instanceof String
|
||||
ok (new Number) not instanceof String
|
||||
|
|
Loading…
Reference in New Issue