(experimental) made `new` a unary operator

This commit is contained in:
satyr 2010-09-25 17:39:19 +09:00
parent 9a3b736174
commit c24e1eacb9
10 changed files with 32 additions and 42 deletions

View File

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

View File

@ -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']];

View File

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

View File

@ -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 = ['<=', '<', '>', '>='];

View File

@ -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() {

View File

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

View File

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

View File

@ -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 = ['&', '|', '^', '&&', '||']

View File

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

View File

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